SpringBoot与Shiro整合-权限管理实战

    xiaoxiao2022-07-14  153

    场景

    SpringBoot与Shiro整合-权限管理实战。

    实现

    搭建SpringBoot运行环境

    打开Eclipse,new Maven Project--Create a simple project

    输入项目相关信息,Packing 选择为jar,点击Finish。

    修改项目的编译环境为1.8

    打开项目的pom.xml

     <!-- 修改参数 -->   <properties>    <!-- 修改JDK的编译版本为1.8 -->    <java.version>1.8</java.version>   </properties>

    添加之后--右击项目-Maven-update Project

    添加父级依赖

    打开pom.xml

    <parent>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-parent</artifactId>    <version>1.5.4.RELEASE</version>   </parent>

    添加项目依赖

    打开pom.xml

     <dependencies>     <!-- 导入web支持 -->    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->  <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-web</artifactId>  </dependency>   </dependencies>

    完整pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">   <modelVersion>4.0.0</modelVersion>     <parent>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-parent</artifactId>    <version>1.5.4.RELEASE</version>   </parent>   <groupId>com.badao.springboot</groupId>   <artifactId>springboot-shiro</artifactId>   <version>0.0.1-SNAPSHOT</version>     <dependencies>     <!-- 导入web支持 -->    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->  <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-web</artifactId>  </dependency>   </dependencies>   <!-- 修改参数 -->   <properties>    <!-- 修改JDK的编译版本为1.8 -->    <java.version>1.8</java.version>   </properties> </project>

    测试SpringBoot搭建效果

    在src/main/java下新建UserController

    代码:

    package com.badao.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class UserController {  /***   * usercontroller测试   */  @RequestMapping("/hello")  @ResponseBody  public String hello() {   System.out.println("**********************hello");   return "hello";  } }

    新建项目启动类Application.java,要与UserController同级

    package com.badao; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /**  * springboot启动类  * @author badao  * @Description:  * @Time:2019年5月19日 下午4:20:07  */ @SpringBootApplication public class Application {  public static void main(String[] args) {   SpringApplication.run(Application.class,args);  } }

    运行启动类

    启动效果

    打开浏览器访问

    http://localhost:8080/hello

     

    引进Thymeleaf模板

    打开pom.xml

    <!-- thymeleaf-->  <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf -->  <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-thymeleaf</artifactId>     </dependency>

    在src/main/resources下新建templates目录,目录下新建test.html

    代码:

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"></meta> <title>Thymeleaf 使用</title> </head> <body> <h3 th:text="${username}"></h3> </body> </html>

    注意:

    在thymeleaf3.0以前对页面标签语法要求比较严格开始标签必须有结束标签。

    所以这里手动加上</meta>结束标签。

    或者这里升级thymeleaf为3.0或更高。

    具体参照:

    https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/90344773

    在UserController中新建测试方法

    /***   * Thymeleaf测试   */  @RequestMapping("/testThymeleaf")  public String testThymeleaf(Model model) {   model.addAttribute("username","badao");   return "test";  }

    运行效果

    启动启动类,打开浏览器输入:

    http://localhost:8080/testThymeleaf

     

    Shiro认证-ShiroConfig配置类

    自定义Realm

    新建包shiro,包下新建UserRealm.java

    package com.badao.shiro; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; /***  * 自定义Realm  * @author Administrator  * @Description:  * @Time:2019年5月19日 下午6:34:50  */ public class UserRealm extends AuthorizingRealm{  /***   * 执行授权逻辑   */  @Override  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {   // TODO Auto-generated method stub   System.out.println("执行授权逻辑");   return null;  }  /***   * 执行认证逻辑   */  @Override  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {   // TODO Auto-generated method stub   System.out.println("执行认证逻辑");   return null;  } }

    ShiroConfig配置类

    shiro包下新建ShiroConfig.java配置类

    package com.badao.shiro; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /***  * Shiro配置类  * @author Administrator  * @Description:  * @Time:2019年5月19日 下午6:33:48  */ @Configuration public class ShiroConfig {    /***   * 创建ShiroFilterFactoryBean   * @return   */ @Bean  public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager) {   ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();   //设置安全管理器   shiroFilterFactoryBean.setSecurityManager(securityManager);   return shiroFilterFactoryBean;  }    /***   * 创建DefaultWebSecurityManager   * @return   */  @Bean(name="securityManager")  public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm) {   DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();   //关联realm   securityManager.setRealm(userRealm);   return securityManager;  }  /***   * 创建Realm   * @return   */  @Bean(name="userRealm")  public UserRealm getRealm() {   return new UserRealm();   } }

    注:

    通过@Bean(name="userRealm")实现添加到spring容器,然后通过@Qualifier("userRealm")去引用。

    使用Shiro过滤器实现认证资源拦截

    打开test.html,添加两个超链接。

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"></meta> <title>Thymeleaf 使用</title> </head> <body> <h3 th:text="${username}"></h3> <br> <a href="add">添加</a> <a href="update">更新</a> </body> </html>

    注:

    进行页面的跳转时不能直接跳转到具体的页面,必须经过controller跳转。

    templates下新建user目录,目录下新建add.html

     <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>添加用户</title> </head> <body> <h1>开始添加用户</h1> </body> </html>

    再新建update.html

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>编辑用户</title> </head> <body> <h1>开始编辑用户</h1> </body> </html>

    来到UserController中,添加跳转页面方法。

    /***   * 跳转到add   */  @RequestMapping("/add")  public String add() {    return "user/add";  }  /***   * 跳转到update   */  @RequestMapping("/update")  public String update() {    return "user/update";  }

    运行项目,打开浏览器输入:

    http://localhost:8080/testThymeleaf

     

    开始添加权限认证

    需求:

    访问首页即testThymeleaf时不进行验证,访问添加和编辑时进行拦截跳转到登录页面。

    template下新建login.html

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <h1>请登录</h1> </body> </html>

    打开ShiroConfig配置文件

    添加Shiro内置过滤器:

    1.anon:无需认证可以访问。

    2.authc:必须认证才可以 访问。

    3.user:如果使用rememberMe的功能可以直接访问。

    4.perms:该资源必须得到资源权限才可以访问。

    5.role:该资源必须得到角色权限才可以访问。

    在getShiroFilterFactoryBean中:

    @Bean  public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager) {   ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();      //设置安全管理器   shiroFilterFactoryBean.setSecurityManager(securityManager);   //添加Shiro内置过滤器     Map<String, String> filterMap = new LinkedHashMap<String, String>();   filterMap.put("/add", "authc");   filterMap.put("/update", "authc");   //上面两行可以用通配符来配置   //filterMap.put("/*", "authc");   //不拦截首页   filterMap.put("/testThymeleaf", "anon");   shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);   //修改调整的登录页面   shiroFilterFactoryBean.setLoginUrl("/login");   return shiroFilterFactoryBean;  }

    在UserController中添加登录跳转

    /***   * 跳转到login   */  @RequestMapping("/login")  public String login() {    return "login";  }

    启动项目,输入:

    http://localhost:8080/testThymeleaf

    效果

    实现用户认证(登录)操作

    编写login.html

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <h1>请登录</h1> <font color="red" th:text="${msg}"></font> <form action="dologin" method="post">  用户名:<input type="text" name="name"><br>  密码:<input type="password" name="password"><br>  <input type="submit" value="提交"> </form> </body> </html>

    UserController中添加登录方法

    /***   * login   */  @RequestMapping("/dologin")  public String dologin(String name,String password,Model model) {       /***    * 使用Shiro编写认证操作    *    */   //1.获取Subject   Subject subject = SecurityUtils.getSubject();      //2.封装用户数据   UsernamePasswordToken token = new UsernamePasswordToken(name,password);      //3.执行登录方法   try {    //登录成功,没有异常代表登录成功    //login方法会来到UserRealm中的执行认证的方法    subject.login(token);    return "redirect:/testThymeleaf";   }catch (UnknownAccountException e) {    //登录失败:用户名不存在    model.addAttribute("msg","用户名不存在");    return "/login";   }catch (IncorrectCredentialsException e){    //登录失败:密码不正确    model.addAttribute("msg","密码不正确");    return "/login";   }        }

    注:

    1.subject.login(token)会自动找到自定义Realm中的执行认证的方法。

    2.没有异常就是登录成功,出现UnknownAccountException 就是用户名不正确,出现IncorrectCredentialsException 就是密码不正确。

    修改UserRealm

    /***   * 执行认证逻辑   */  @Override  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken args) throws AuthenticationException {   // TODO Auto-generated method stub   System.out.println("执行认证逻辑");   //假设数据库用户名和密码   String name = "badao";   String password = "123";      //1.判断用户名   UsernamePasswordToken token = (UsernamePasswordToken) args;   if(!token.getUsername().equals(name)){    //用户名不存在    //shiro底层会抛出UnknownAccountException    return null;   }   //2.判断密码   //编写shiro判断逻辑   return new SimpleAuthenticationInfo("",password,"");  }

    在配置文件中给登录放行

    Map<String, String> filterMap = new LinkedHashMap<String, String>();   filterMap.put("/add", "authc");   filterMap.put("/update", "authc");   //上面两行可以用通配符来配置   //filterMap.put("/*", "authc");   //不拦截首页   filterMap.put("/testThymeleaf", "anon");   filterMap.put("/dologin", "anon");

    运行项目,打开浏览器输入:

    http://localhost:8080/testThymeleaf

    效果

     

    整合MyBatis实现用户登录

    导入MyBatis相关的依赖

    打开pom.xml

    <!-- 导入Mybatis相关依赖 -->  <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->  <dependency>      <groupId>com.alibaba</groupId>      <artifactId>druid</artifactId>      <version>1.0.9</version>  </dependency>  <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->  <dependency>      <groupId>mysql</groupId>      <artifactId>mysql-connector-java</artifactId>      <version>8.0.11</version>  </dependency>  <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->  <dependency>      <groupId>org.mybatis.spring.boot</groupId>      <artifactId>mybatis-spring-boot-starter</artifactId>      <version>1.1.1</version>  </dependency>

    数据库中新建表

    新建表Users

    配置application.properties

    在src/main/resources下新建application.properties

    名字与位置必须一致。

    代码:

    spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/shirotest?useUnicode=true&characterEncoding=UTF-8&useSSL=false spring.datasource.username=root spring.datasource.password=123 #配置数据源 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource #配置别名 mybatis.type-aliases-package=com.badao.entity

    新建entiry

    新建entity包,包下新建User.java

    package com.badao.entity; public class User {    int id;  String userName;  String password;  public int 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;  }   }

    编写mapper

    新建mapper包,包下新建UserMapper接口

    package com.badao.mapper; import com.badao.entity.User; public interface UserMapper {  public User findByName(String name); }

    再在此包新新建UserMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.badao.mapper.UserMapper"> <select id="findByName" resultType="user" parameterType="String"> select * from users where userName =#{value} </select> </mapper>

    编写service

    新建service包,包下新建UserService接口

    package com.badao.service; import com.badao.entity.User; public interface UserService {  public User findByName(String name); }

    再在此包下新建UserServiceImpl

    package com.badao.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.badao.entity.User; import com.badao.mapper.UserMapper; @Service public class UserServiceImpl implements UserService {  @Autowired  private UserMapper userMapper;  @Override  public User findByName(String name) {   // TODO Auto-generated method stub   return userMapper.findByName(name);  } }

    修改Controller

    打开UserController,添加如下登录方法。

    /***   * 跳转到login   */  @RequestMapping("/login")  public String login() {    return "login";  }    /***   * login   */  @RequestMapping("/dologin")  public String dologin(String name,String password,Model model) {       /***    * 使用Shiro编写认证操作    *    */   //1.获取Subject   Subject subject = SecurityUtils.getSubject();      //2.封装用户数据   UsernamePasswordToken token = new UsernamePasswordToken(name,password);      //3.执行登录方法   try {    //登录成功,没有异常代表登录成功    //login方法会来到UserRealm中的执行认证的方法    subject.login(token);    return "redirect:/testThymeleaf";   }catch (UnknownAccountException e) {    //登录失败:用户名不存在    model.addAttribute("msg","用户名不存在");    return "/login";   }catch (IncorrectCredentialsException e){    //登录失败:密码不正确    model.addAttribute("msg","密码不正确");    return "/login";   }        }

    修改Realm

    打开UserRealm.java,修改为:

    /***   * 执行认证逻辑   */  @Override  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken args) throws AuthenticationException {   // TODO Auto-generated method stub   System.out.println("执行认证逻辑");   //假设数据库用户名和密码   /*String name = "badao";   String password = "123";*/   UsernamePasswordToken token = (UsernamePasswordToken) args;   User user = userService.findByName(token.getUsername());   //1.判断用户名      if(user==null){    //用户名不存在    //shiro底层会抛出UnknownAccountException    return null;   }   //2.判断密码   //编写shiro判断逻辑   return new SimpleAuthenticationInfo("",user.getPassword(),"");  }

    修改ShiroConfig

    打开ShiroConfig,放开登录页面

    Map<String, String> filterMap = new LinkedHashMap<String, String>();   filterMap.put("/add", "authc");   filterMap.put("/update", "authc");   //上面两行可以用通配符来配置   //filterMap.put("/*", "authc");   //不拦截首页   filterMap.put("/testThymeleaf", "anon");   filterMap.put("/login", "anon");   shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);

    修改login.html

    <body> <h1>请登录</h1> <font color="red" th:text="${msg}"></font> <form action="dologin" method="post">  用户名:<input type="text" name="name"><br>  密码:<input type="password" name="password"><br>  <input type="submit" value="提交"> </form> </body>

    修改启动类

    打开Application.java,添加@MapperScan("com.badao.mapper"):

    @SpringBootApplication @MapperScan("com.badao.mapper") public class Application {  public static void main(String[] args) {   SpringApplication.run(Application.class,args);  } }

    整合MyBatis后项目结构

    整合MyBatis后效果

    使用Shiro过滤器实现授权页面拦截

    修改配置文件

    打开ShiroConfig配置文件,添加授权过滤器。

    //授权过滤器   //注意:当授权拦截后,shiro会自动跳转到未授权页面   filterMap.put("/add", "perms[user:add]");

    设置未授权提示页面

    shiroFilterFactoryBean.setUnauthorizedUrl("/unAuth");

    打开UserController,添加未授权页面跳转

    /***   * 跳转到未授权页面   */  @RequestMapping("/login")  public String login() {    return "login";  }

    在templates下新建unAuth.html

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>没有授权</title> </head> <body> <h1>没有授权</h1> </body> </html>

    运行效果

    编写资源授权逻辑

    修改UserRealm

    /***   * 执行授权逻辑   */  @Override  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {   // TODO Auto-generated method stub   System.out.println("执行授权逻辑");      //给资源进行授权   SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();      //添加资源的授权字符串   info.addStringPermission("user:add");      return info;  }

    注意:

    添加资源的授权字符串要与上面进行拦截的字符串一致才能跳过拦截。

    效果:

    关联数据库实现动态授权

    为了简单的进行测试,不再建立角色表与权限表。

    改造Users表

    直接添加权限列。

    授予badao用户 user:add权限

    授予liumang用户 user:update权限

    改造User.java实体类

    package com.badao.entity; public class User {    int id;  String userName;  String password;  public String getPerms() {   return perms;  }  public void setPerms(String perms) {   this.perms = perms;  }  String perms;  public int 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;  }   }

    UserMapper.xml中添加方法

    <select id="findById" resultType="user" parameterType="int"> select * from users where id =#{value} </select>

    UserMapper接口中添加方法

    public User findById(int id);

    UserService中添加方法

    public User findById(int id);

    UserServiceImpl实现方法

    @Override  public User findById(int id) {   // TODO Auto-generated method stub   return userMapper.findById(id);  }

    添加更新的权限拦截

    打开Shiroconfig.java

    //注意:当授权拦截后,shiro会自动跳转到未授权页面   filterMap.put("/add", "perms[user:add]");   filterMap.put("/update", "perms[user:update]");

    执行授权逻辑查询数据库修改

    打开UserRealm.java

    /***   * 执行授权逻辑   */  @Override  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {   // TODO Auto-generated method stub   System.out.println("执行授权逻辑");      //给资源进行授权   SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();      //添加资源的授权字符串   //info.addStringPermission("user:add");   //获取当前登录用户   Subject subject = SecurityUtils.getSubject();   User user = (User)subject.getPrincipal();   userService.findById(user.getId());   info.addStringPermission(user.getPerms());   return info;  }

    注:

    User user = (User)subject.getPrincipal();这句中的getPrincipal()就是获取下面执行逻辑认证的

    return new SimpleAuthenticationInfo(user,user.getPassword(),"");

    第一个参数。

    效果

    Thymeleaf整合Shiro权限标签

    导入thymeleaf扩展坐标

    打开pom.xml

    <dependency>      <groupId>com.github.theborakompanioni</groupId>      <artifactId>thymeleaf-extras-shiro</artifactId>      <version>2.0.0</version>  </dependency>

    配置ShiroDialect

    打开ShiroConfig

    /***   * 配置ShiroDialect 用于thymeleaf和Shiro便签配合使用   */  @Bean  public ShiroDialect getShiroDialect() {   return new ShiroDialect();     }

    页面中使用

    打开test.html

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"></meta> <title>Thymeleaf 使用</title> </head> <body> <h3 th:text="${username}"></h3> <br> <div shiro:hasPermission="user:add"> <a href="add">添加</a> </div> <div shiro:hasPermission="user:update"> <a href="update">更新</a> </div> <br> <a href="login">登录</a> </body> </html>

    效果

     

    源码下载

    https://download.csdn.net/download/badao_liumang_qizhi/11194439

     

    最新回复(0)