Springboot整合Shiro之認證

  • 2019 年 12 月 2 日
  • 筆記

版權聲明:本文為部落客原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。

本文鏈接:https://dpb-bobokaoya-sm.blog.csdn.net/article/details/103322744

Shiro是我們常用的一個許可權管理框架,我們之前已經詳細的給大家介紹過了Shiro的基礎知識,不太清楚的可以參考下 https://blog.csdn.net/qq_38526573/category_9284714.html 此文,本文的重點是來介紹下在SpringBoot環境下我們怎麼來使用Shiro。

一、添加相關依賴

本案例中我們使用SpringDataJPAThymeleaf來配合講解,所以相關的依賴如下

<dependencies>      <dependency>          <groupId>org.springframework.boot</groupId>          <artifactId>spring-boot-starter-web</artifactId>      </dependency>        <dependency>          <groupId>org.springframework.boot</groupId>          <artifactId>spring-boot-starter-test</artifactId>          <scope>test</scope>          <exclusions>              <exclusion>                  <groupId>org.junit.vintage</groupId>                  <artifactId>junit-vintage-engine</artifactId>              </exclusion>          </exclusions>      </dependency>      <dependency>          <groupId>org.apache.shiro</groupId>          <artifactId>shiro-spring</artifactId>          <version>1.3.2</version>      </dependency>      <!-- springBoot的啟動器 -->      <dependency>          <groupId>org.springframework.boot</groupId>          <artifactId>spring-boot-starter-data-jpa</artifactId>      </dependency>      <!-- mysql -->      <dependency>          <groupId>mysql</groupId>          <artifactId>mysql-connector-java</artifactId>          <version>5.1.47</version>      </dependency>        <!-- druid連接池 -->      <dependency>          <groupId>com.alibaba</groupId>          <artifactId>druid</artifactId>          <version>1.0.9</version>      </dependency>      <dependency>          <groupId>org.springframework.boot</groupId>          <artifactId>spring-boot-starter-thymeleaf</artifactId>      </dependency>  </dependencies>

二、添加相關的配置資訊

  在application.properties中添加如下的配置資訊

# jdbc 的相關資訊  spring.datasource.driverClassName=com.mysql.jdbc.Driver  spring.datasource.url=jdbc:mysql://localhost:3306/srm?characterEncoding=utf-8  spring.datasource.username=root  spring.datasource.password=123456    # 配置連接池資訊  spring.datasource.type=com.alibaba.druid.pool.DruidDataSource    # 配置jpa的相關參數  spring.jpa.hibernate.ddl-auto=update  spring.jpa.show-sql=true

三、業務準備

  我們提前將登錄認證的後台業務先完成。我們提前將登錄認證的後台業務先完成。

1.對應的表結構

CREATE TABLE `t_user` (    `id` int(20) NOT NULL AUTO_INCREMENT,    `username` varchar(20) DEFAULT NULL,    `password` varchar(100) DEFAULT NULL,    `salt` varchar(100) DEFAULT NULL,    `create_time` datetime DEFAULT NULL,    `state` int(1) DEFAULT NULL,    `last_login_time` datetime DEFAULT NULL,    `nickname` varchar(30) DEFAULT NULL,    `realname` varchar(255) DEFAULT NULL,    PRIMARY KEY (`id`)  ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

2.pojo對象

package com.dpb.springboot41shiro.pojo;    import javax.persistence.*;    /**   * @program: springboot-41-shiro   * @description:   * @author: 波波烤鴨   * @create: 2019-11-29 20:06   */  @Entity  @Table(name = "t_user")  public class User {        @Id      @GeneratedValue(strategy = GenerationType.IDENTITY)      @Column(name = "id")      private Integer id;      @Column(name = "username")      private String username;      @Column(name = "password")      private String password;      @Column(name = "salt")      private String salt;      @Column(name = "realname")      private String realname;        public Integer getId() {          return id;      }        public void setId(Integer id) {          this.id = id;      }        public String getUsername() {          return username;      }        public void setUsername(String username) {          this.username = username;      }        public String getPassword() {          return password;      }        public void setPassword(String password) {          this.password = password;      }        public String getSalt() {          return salt;      }        public void setSalt(String salt) {          this.salt = salt;      }        public String getRealname() {          return realname;      }        public void setRealname(String realname) {          this.realname = realname;      }  }

3.dao介面

  介面我們通過 JpaRepository介面來實現,然後根據名稱規則來定義方法

public interface UserDao extends JpaRepository<User,Integer> {        /**       * 根據帳號查詢       * @param username       * @return       */      List<User> findByUsername(String username);  }

4.業務層程式碼

  業務層就實現簡單的調用即可

四、Shiro整合

  接下來我們就可以來整合Shiro框架了

1.自定義Realm文件

  首先我們定義一個realm實現類來實現我們認證和授權的邏輯

package com.dpb.springboot41shiro.realm;    import com.dpb.springboot41shiro.pojo.User;  import com.dpb.springboot41shiro.service.UserService;  import org.apache.shiro.authc.*;  import org.apache.shiro.authz.AuthorizationInfo;  import org.apache.shiro.realm.AuthorizingRealm;  import org.apache.shiro.subject.PrincipalCollection;  import org.apache.shiro.util.SimpleByteSource;  import org.springframework.beans.factory.annotation.Autowired;    import java.util.List;    /**   * @program: springboot-41-shiro   * @description: 自定義Realm   * @author: 波波烤鴨   * @create: 2019-11-29 19:37   */  public class AuthcRealm extends AuthorizingRealm {        /**       * 認證的方法       * @param authenticationToken       * @return       * @throws AuthenticationException       */      @Override      protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {                  return null;      }        /**       * 授權的方法       * @param principalCollection       * @return       */      @Override      protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {          return null;      }  }

邏輯可以稍後實現

2.Shiro的配置類

  我們先來看下之前在spring整合shiro的時候,我們的整合配置文件:

那麼我們在SpringBoot中只需將此配置轉換為對應的java配置即可,如下

package com.dpb.springboot41shiro.config;    import com.dpb.springboot41shiro.realm.AuthcRealm;  import org.apache.shiro.authc.credential.HashedCredentialsMatcher;  import org.apache.shiro.mgt.SecurityManager;  import org.apache.shiro.spring.web.ShiroFilterFactoryBean;  import org.apache.shiro.web.mgt.DefaultWebSecurityManager;  import org.springframework.beans.factory.annotation.Value;  import org.springframework.context.annotation.Bean;  import org.springframework.context.annotation.Configuration;    import java.util.HashMap;  import java.util.Map;    /**   * @program: springboot-41-shiro   * @description: Shiro的配置類   * @author: 波波烤鴨   * @create: 2019-11-29 19:31   */  @Configuration  public class ShiroConfig {        @Value("${shiro.hashAlgorithmName}")      private String hashAlgorithmName;        @Value("${shiro.hashIterations}")      private Integer hashIterations;        /**       * 獲取憑證匹配器       * @return       */      @Bean      public HashedCredentialsMatcher hashedCredentialsMatcher(){          HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();          matcher.setHashAlgorithmName(hashAlgorithmName);          matcher.setHashIterations(hashIterations);          return matcher;      }        /**       * 獲取自定義的Realm       * @return       */      @Bean      public AuthcRealm authcRealm(){          AuthcRealm realm = new AuthcRealm();          realm.setCredentialsMatcher(hashedCredentialsMatcher());          return realm;      }        /**       * 獲取SecurityManager對象       * @return       */      @Bean      public SecurityManager securityManager(){          DefaultWebSecurityManager manager = new DefaultWebSecurityManager();          manager.setRealm(authcRealm());          return manager;      }        /**       * 註冊ShiroFilterFactoryBean       * @return       */      @Bean(name = "shiroFilter")      public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager manager){          ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();          filter.setSecurityManager(manager);          filter.setLoginUrl("/login.do");          filter.setSuccessUrl("/success.html");          filter.setUnauthorizedUrl("/refuse.html");          // 設置過濾器          Map<String,String> map = new HashMap<>();          map.put("/css/**","anon");          map.put("/img/**","anon");          map.put("/js/**","anon");          map.put("/login","anon");          map.put("/login.do","authc");          map.put("/**","authc");          filter.setFilterChainDefinitionMap(map);          return filter;      }  }

3.訪問測試

  到此shiro已經被集成到了我們項目中,我們可以根據我們配置的過濾鏈路來啟動訪問下,首先創建如下的相關文件,便於測試

同時添加對應的跳轉控制器

/**   * @program: springboot-41-shiro   * @description: 基礎控制器   * @author: 波波烤鴨   * @create: 2019-11-29 19:52   */  @Controller  public class BaseController {        @RequestMapping("/{path}")      public String page(@PathVariable  String path){          return path;      }  }

訪問需要認證的success.html ,會給錯誤提示 訪問img/a2.jpg可以直接訪問

五、登錄認證測試

  接下來我們實現下認證的過程。

1.自定義realm實現登錄

  自定義realm認證的流程如下

@Autowired  private UserService service;    /**   * 認證的方法   * @param authenticationToken   * @return   * @throws AuthenticationException   */  @Override  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {      UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;      String userName = token.getUsername();      System.out.println("開始登錄認證:"+userName);      List<User> list = service.login(userName);      if (list == null || list.size() != 1) {          return null;      }      User user = list.get(0);        return new SimpleAuthenticationInfo(user,user.getPassword(),new SimpleByteSource(user.getSalt()),"authcRealme");  }

2.創建登錄表單

  前端我們用Thymeleaf來作為模組框架,創建登錄表單

<!DOCTYPE html>  <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" >  <head>      <meta charset="UTF-8">      <title>Title</title>  </head>  <body>      <h1>登錄管理</h1>      <form th:action="@{/login.do}" method="post">          帳號:<input type="text" name="username"><br>          密碼:<input type="text" name="password"><br>          <input type="submit" value="登錄">      </form>  </body>  </html>

3.創建認證的控制器

  同時我們創建認證的控制器,來處理認證失敗的情況

package com.dpb.springboot41shiro.controller;    import org.apache.shiro.SecurityUtils;  import org.apache.shiro.crypto.hash.Md5Hash;  import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;  import org.springframework.stereotype.Controller;  import org.springframework.web.bind.annotation.RequestMapping;    import javax.servlet.http.HttpServletRequest;    /**   * @program: springboot-41-shiro   * @description: 認證的控制器   * @author: 波波烤鴨   * @create: 2019-11-29 20:12   */  @Controller  public class AuthcController {        @RequestMapping("/login.do")      public String login(HttpServletRequest request){          Object obj = request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);          System.out.println("認證的錯誤資訊:" + obj);          return "/login";      }        /**       * 註銷的方法       * @return       */      @RequestMapping("/logout.do")      public String logout(){          SecurityUtils.getSubject().logout();          return "redirect:/login";      }  }

4.準備數據

  我們可以自己通過Md5加密一個密碼然後保存到資料庫中

5.測試

到此啟動項目,登錄測試即可

最後項目的目錄結構如下: