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.测试

到此启动项目,登录测试即可

最后项目的目录结构如下: