当前位置:   article > 正文

springboot整合shiro入门,实现认证和授权功能(非常详细)_spring boot shiro

spring boot shiro

Shiro和Spring Security应该是我们比较常用的权限框架了,这篇文章教大家怎么通过springboot整合shiro从零开始搭建一个包含权限控制的后台管理系统。

目录

第一步:创建springboot项目

第二步:添加maven的依赖

第三步:修改配置文件

第四步:创建数据库表

第五步:创建表user对应类

第六步:创建UserRealm

第七步:创建Shiro配置类

第八步:实现登录功能

控制器层

业务层

UserRealm

持久层

第九步:测试登录功能

login.html

login.js

home.html

ShiroConfig.java

第十步:实现授权功能

UserRealm.java

UserController.java

/html/home.html 

自定义过滤器实现鉴权

ShiroConfig.java

第十一步:测试鉴权功能



第一步:创建springboot项目

通过IntelliJ IDEA创建一个springboot项目,这里的项目就命名为springboot-shiro

第二步:添加maven的依赖

修改pom.xml,添加相关的maven依赖

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.5.9</version>
  9. <relativePath />
  10. </parent>
  11. <groupId>cn.edu.sgu.www</groupId>
  12. <artifactId>springboot-shiro</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>springboot-shiro</name>
  15. <description>Spring Boot整合Shiro权限认证框架</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. <shiro.version>1.3.2</shiro.version>
  19. <mysql.version>8.0.28</mysql.version>
  20. <druid.version>1.1.21</druid.version>
  21. <lombok.version>1.18.22</lombok.version>
  22. <fastjson.version>2.0.8</fastjson.version>
  23. <mybatis.version>2.2.2</mybatis.version>
  24. </properties>
  25. <dependencies>
  26. <dependency>
  27. <groupId>org.springframework.boot</groupId>
  28. <artifactId>spring-boot-starter-web</artifactId>
  29. </dependency>
  30. <!--lombok-->
  31. <dependency>
  32. <groupId>org.projectlombok</groupId>
  33. <artifactId>lombok</artifactId>
  34. <version>${lombok.version}</version>
  35. </dependency>
  36. <!--mysql-->
  37. <dependency>
  38. <groupId>mysql</groupId>
  39. <artifactId>mysql-connector-java</artifactId>
  40. <version>${mysql.version}</version>
  41. </dependency>
  42. <!--mybatis-->
  43. <dependency>
  44. <groupId>org.mybatis.spring.boot</groupId>
  45. <artifactId>mybatis-spring-boot-starter</artifactId>
  46. <version>${mybatis.version}</version>
  47. </dependency>
  48. <!--druid-->
  49. <dependency>
  50. <groupId>com.alibaba</groupId>
  51. <artifactId>druid</artifactId>
  52. <version>${druid.version}</version>
  53. </dependency>
  54. <!--fastjson-->
  55. <dependency>
  56. <groupId>com.alibaba</groupId>
  57. <artifactId>fastjson</artifactId>
  58. <version>${fastjson.version}</version>
  59. </dependency>
  60. <!-- shiro -->
  61. <dependency>
  62. <groupId>org.apache.shiro</groupId>
  63. <artifactId>shiro-spring</artifactId>
  64. <version>${shiro.version}</version>
  65. </dependency>
  66. </dependencies>
  67. <build>
  68. <plugins>
  69. <plugin>
  70. <groupId>org.springframework.boot</groupId>
  71. <artifactId>spring-boot-maven-plugin</artifactId>
  72. </plugin>
  73. </plugins>
  74. </build>
  75. </project>

完成前面两步之后,删除多余的test包,项目结构如图:

第三步:修改配置文件

修改系统的配置文件application.yml(修改默认的配置文件application.properties的名称为application.yml,只需要改后缀名),修改完成之后,把以下内容复制到application.yml中。

  1. spring:
  2. profiles:
  3. active: dev
  4. # mybatis的mapper.xml文件的位置
  5. mybatis:
  6. mapper-locations: classpath:mapper/*Mapper.xml

最后再新建一个application-dev.yml

  1. # 设置启动端口号
  2. server:
  3. port: 8080
  4. spring:
  5. # 配置数据源
  6. datasource:
  7. username: root
  8. password: root
  9. url: jdbc:mysql://localhost:3306/springboot-shiro
  10. driver-class-name: com.mysql.cj.jdbc.Driver
  11. type: com.alibaba.druid.pool.DruidDataSource
  12. # 只返回不为null的数据
  13. jackson:
  14. default-property-inclusion: non_null

第四步:创建数据库表

1、通过navicat数据库连接工具新建数据库springboot-shiro,没有用过navicat的童鞋可以参考博主的文章推荐一款非常简单实用的数据库连接工具Navicat Premiumicon-default.png?t=N7T8https://blog.csdn.net/heyl163_/article/details/132111378

2、在springboot-shiro数据库下创建用户表user

  1. -- ----------------------------
  2. -- Table structure for user
  3. -- ----------------------------
  4. DROP TABLE IF EXISTS `user`;
  5. CREATE TABLE `user` (
  6. `id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  7. `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '姓名',
  8. `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名',
  9. `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '12345' COMMENT '密码',
  10. `phone` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '手机号',
  11. `gender` tinyint(4) UNSIGNED NOT NULL COMMENT '性别',
  12. `is_enable` tinyint(4) UNSIGNED NOT NULL COMMENT '启用状态',
  13. `last_login_time` datetime NULL DEFAULT NULL COMMENT '上一次登录时间',
  14. PRIMARY KEY (`id`) USING BTREE
  15. ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
  16. -- ----------------------------
  17. -- Records of user
  18. -- ----------------------------
  19. INSERT INTO `user` VALUES ('2023', '系统管理员', 'system', '', '18888888888', 2, 1, '2022-11-25 00:15:42');
  20. INSERT INTO `user` VALUES ('mhxy1218', '沐雨橙风ιε', 'mumu', 'mhxy1218', '16666666666', 1, 1, '2023-07-02 00:00:29');

第五步:创建表user对应类

  • 数据库表对应实体类:User
  • 持久层接口:UserMapper
  • 业务层接口及实现类:Userservice、UserServiceImpl
  • 控制器类:UserController

配置mapper包扫描路径

在springboot的启动类或者任意一个配置类上使用注解@MapperScan注解配置mybatis的mapper包扫描路径

@MapperScan("cn.edu.sgu.www.shiro.mapper")

在项目根目录下创建一个config包,在config包下面创建一个MybatisConfig类。

  1. package cn.edu.sgu.www.shiro.config;
  2. import org.mybatis.spring.annotation.MapperScan;
  3. import org.springframework.context.annotation.Configuration;
  4. /**
  5. * mybatis配置类
  6. * @author heyunlin
  7. * @version 1.0
  8. */
  9. @Configuration
  10. @MapperScan("cn.edu.sgu.www.shiro.mapper")
  11. public class MybatisConfig {
  12. }

第六步:创建UserRealm

项目根目录下创建realm包,在realm包下创建UserRealm.java,并继承AuthorizingRealm,实现AuthorizingRealm的两个认证和授权的抽象方法。

  1. package cn.edu.sgu.www.shiro.realm;
  2. import org.apache.shiro.authc.AuthenticationException;
  3. import org.apache.shiro.authc.AuthenticationInfo;
  4. import org.apache.shiro.authc.AuthenticationToken;
  5. import org.apache.shiro.authz.AuthorizationInfo;
  6. import org.apache.shiro.realm.AuthorizingRealm;
  7. import org.apache.shiro.subject.PrincipalCollection;
  8. import org.springframework.stereotype.Component;
  9. /**
  10. * @author heyunlin
  11. * @version 1.0
  12. */
  13. @Component
  14. public class UserRealm extends AuthorizingRealm {
  15. /**
  16. * 认证
  17. */
  18. @Override
  19. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
  20. return null;
  21. }
  22. /**
  23. * 授权
  24. */
  25. @Override
  26. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
  27. return null;
  28. }
  29. }

第七步:创建Shiro配置类

在config包下创建ShiroConfig.java

  1. package cn.edu.sgu.www.shiro.config;
  2. import cn.edu.sgu.www.shiro.realm.UserRealm;
  3. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
  4. import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. /**
  8. * shiro配置类
  9. */
  10. @Configuration
  11. public class ShiroConfig {
  12. /**
  13. * 配置安全管理器
  14. * @param userRealm UserRealm
  15. * @return DefaultWebSecurityManager
  16. */
  17. @Bean
  18. public DefaultWebSecurityManager securityManager(UserRealm userRealm) {
  19. DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
  20. securityManager.setRealm(userRealm);
  21. return securityManager;
  22. }
  23. /**
  24. * 配置Shiro过滤器工厂
  25. * @param securityManager 安全管理器
  26. * @return ShiroFilterFactoryBean
  27. */
  28. @Bean
  29. public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
  30. ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
  31. // 注册安全管理器
  32. shiroFilterFactoryBean.setSecurityManager(securityManager);
  33. /*
  34. * 设置登录页面的地址
  35. * 当用户访问认证资源的时候,如果用户没有登录,那么就会跳转到该属性指定的页面
  36. */
  37. shiroFilterFactoryBean.setLoginUrl("/login.html");
  38. return shiroFilterFactoryBean;
  39. }
  40. }

第八步:实现登录功能

控制器层

在UserController类中添加一个login()方法,新建UserLoginDTO对象来接收前端传来的用户名和密码,同时通过validation验证这两个字段。

  1. package cn.edu.sgu.www.shiro.controller;
  2. import cn.edu.sgu.www.shiro.dto.UserLoginDTO;
  3. import cn.edu.sgu.www.shiro.restful.JsonResult;
  4. import cn.edu.sgu.www.shiro.service.UserService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.bind.annotation.RequestMethod;
  8. import org.springframework.web.bind.annotation.RestController;
  9. /**
  10. * @author heyunlin
  11. * @version 1.0
  12. */
  13. @RestController
  14. @RequestMapping(path = "/user", produces = "application/json;charset=utf-8")
  15. public class UserController {
  16. private final UserService userService;
  17. @Autowired
  18. public UserController(UserService userService) {
  19. this.userService = userService;
  20. }
  21. @RequestMapping(path = "/login", method = RequestMethod.POST)
  22. public JsonResult<Void> login(UserLoginDTO loginDTO) {
  23. userService.login(loginDTO);
  24. return JsonResult.success();
  25. }
  26. }

业务层

  1. package cn.edu.sgu.www.shiro.service;
  2. import cn.edu.sgu.www.shiro.dto.UserLoginDTO;
  3. /**
  4. * @author heyunlin
  5. * @version 1.0
  6. */
  7. public interface UserService {
  8. /**
  9. * 登录认证
  10. * @param loginDTO 登录信息
  11. */
  12. void login(UserLoginDTO loginDTO);
  13. }

UserServiceImpl中实现用户登录的业务代码,当我们调用Subject的login()方法时,会执行UserRealm下面的认证方法doGetAuthenticationInfo()

  1. package cn.edu.sgu.www.shiro.service.impl;
  2. import cn.edu.sgu.www.shiro.dto.UserLoginDTO;
  3. import cn.edu.sgu.www.shiro.entity.User;
  4. import cn.edu.sgu.www.shiro.exception.GlobalException;
  5. import cn.edu.sgu.www.shiro.mapper.UserMapper;
  6. import cn.edu.sgu.www.shiro.restful.ResponseCode;
  7. import cn.edu.sgu.www.shiro.service.UserService;
  8. import org.apache.shiro.SecurityUtils;
  9. import org.apache.shiro.authc.UsernamePasswordToken;
  10. import org.apache.shiro.subject.Subject;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import org.springframework.stereotype.Service;
  13. /**
  14. * @author heyunlin
  15. * @version 1.0
  16. */
  17. @Service
  18. public class UserServiceImpl implements UserService {
  19. private final UserMapper userMapper;
  20. @Autowired
  21. public UserServiceImpl(UserMapper userMapper) {
  22. this.userMapper = userMapper;
  23. }
  24. @Override
  25. public void login(UserLoginDTO loginDTO) {
  26. String username = loginDTO.getUsername();
  27. // 根据用户名查询用户信息
  28. User user = userMapper.selectByUsername(username);
  29. if (user != null) {
  30. if (user.getIsEnable()) {
  31. // shiro登录认证
  32. UsernamePasswordToken token = new UsernamePasswordToken(username, loginDTO.getPassword());
  33. Subject subject = SecurityUtils.getSubject();
  34. subject.login(token);
  35. // 设置session失效时间:永不超时
  36. subject.getSession().setTimeout(-1001);
  37. } else {
  38. throw new GlobalException(ResponseCode.FORBIDDEN, "账号已被锁定,禁止登录!");
  39. }
  40. } else {
  41. throw new GlobalException(ResponseCode.NOT_FOUND, "用户名不存在~");
  42. }
  43. }
  44. }

UserRealm

实现认证的方法,当调用Subject.login()方法时,在shiro框架内部会去调用realm的认证方法。

  1. package cn.edu.sgu.www.shiro.realm;
  2. import cn.edu.sgu.www.shiro.entity.User;
  3. import cn.edu.sgu.www.shiro.exception.GlobalException;
  4. import cn.edu.sgu.www.shiro.mapper.UserMapper;
  5. import cn.edu.sgu.www.shiro.restful.ResponseCode;
  6. import org.apache.shiro.authc.AuthenticationInfo;
  7. import org.apache.shiro.authc.AuthenticationToken;
  8. import org.apache.shiro.authc.SimpleAuthenticationInfo;
  9. import org.apache.shiro.authc.UsernamePasswordToken;
  10. import org.apache.shiro.authz.AuthorizationInfo;
  11. import org.apache.shiro.realm.AuthorizingRealm;
  12. import org.apache.shiro.subject.PrincipalCollection;
  13. import org.springframework.beans.factory.annotation.Autowired;
  14. import org.springframework.stereotype.Component;
  15. /**
  16. * @author heyunlin
  17. * @version 1.0
  18. */
  19. @Component
  20. public class UserRealm extends AuthorizingRealm {
  21. private final UserMapper userMapper;
  22. @Autowired
  23. public UserRealm(UserMapper userMapper) {
  24. this.userMapper = userMapper;
  25. }
  26. /**
  27. * 认证
  28. */
  29. @Override
  30. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
  31. UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
  32. // 得到用户名
  33. String username = token.getUsername();
  34. // 根据用户名查询用户信息
  35. User user = userMapper.selectByUsername(username);
  36. if (user == null) {
  37. throw new GlobalException(ResponseCode.BAD_REQUEST, "登录失败,用户不存在~");
  38. }
  39. if (user.getIsEnable()) {
  40. String password = new String(token.getPassword());
  41. if (user.getPassword().equals(password)) {
  42. return new SimpleAuthenticationInfo(user, password, username);
  43. } else {
  44. throw new GlobalException(ResponseCode.BAD_REQUEST, "用户名或密码错误,登录失败!");
  45. }
  46. }
  47. return null;
  48. }
  49. /**
  50. * 授权
  51. */
  52. @Override
  53. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
  54. return null;
  55. }
  56. }

持久层

UserMapper接口新增selectByUsername()方法

  1. package cn.edu.sgu.www.shiro.mapper;
  2. import cn.edu.sgu.www.shiro.entity.User;
  3. import org.springframework.stereotype.Repository;
  4. /**
  5. * @author heyunlin
  6. * @version 1.0
  7. */
  8. @Repository
  9. public interface UserMapper {
  10. /**
  11. * 根据用户名查询用户信息
  12. * @param username 用户名
  13. * @return User 查询到的用户信息
  14. */
  15. User selectByUsername(String username);
  16. }

通过xml的方式绑定sql语句

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3. <mapper namespace="cn.edu.sgu.www.shiro.mapper.UserMapper">
  4. <resultMap id="resultMap" type="cn.edu.sgu.www.shiro.entity.User">
  5. <result column="id" property="id" />
  6. <result column="name" property="name" />
  7. <result column="username" property="username" />
  8. <result column="password" property="password" />
  9. <result column="phone" property="phone" />
  10. <result column="is_enable" property="isEnable" />
  11. <result column="last_login_time" property="lastLoginTime" />
  12. </resultMap>
  13. <select id="selectByUsername" resultMap="resultMap">
  14. select * from user where username = #{username}
  15. </select>
  16. </mapper>

第九步:测试登录功能

创建几个简单的页面试一下效果

准备工作:

在resources目录下创建static目录,存放静态资源文件,在static目录下创建js和html目录,把jquery.min.js复制到js目录下。

login.html

static目录下创建登录页面login.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8" />
  5. <title>登录页面</title>
  6. </head>
  7. <body>
  8. <form id="loginForm">
  9. <table>
  10. <tr>
  11. <td>用户名</td>
  12. <td><input type="text" id="username" /></td>
  13. </tr>
  14. <tr>
  15. <td>密码</td>
  16. <td><input type="password" id="password" /></td>
  17. </tr>
  18. <tr>
  19. <td>
  20. <button type="button" id="login">登录</button>
  21. </td>
  22. <td>
  23. <button type="reset">重置</button>
  24. </td>
  25. </tr>
  26. </table>
  27. </form>
  28. <script src="/js/jquery.min.js"></script>
  29. <script src="/js/login.js"></script>
  30. </body>
  31. </html>

login.js

js目录下创建login.js,点击登录按钮时提交用户的数据到接口/user/login,完成登录操作

  1. $(document).ready(function () {
  2. $("#login").click(function () {
  3. let username = $("#username").val();
  4. let password = $("#password").val();
  5. $.post("/user/login", {
  6. username: username,
  7. password: password
  8. }, function (res) {
  9. if (res.code === 200) {
  10. location.href = "/html/home.html";
  11. }
  12. });
  13. });
  14. });

home.html

html目录下创建一个页面home.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8" />
  5. <title>系统首页</title>
  6. </head>
  7. <body>
  8. <h1>欢迎来到系统首页!</h1>
  9. </body>
  10. </html>

ShiroConfig.java

添加资源访问规则,配置登录页面和登录接口的地址可以不需要登录认证就能访问,同时/html/home.html需要登录才能访问。

  1. package cn.edu.sgu.www.shiro.config;
  2. import cn.edu.sgu.www.shiro.realm.UserRealm;
  3. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
  4. import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. import java.util.LinkedHashMap;
  8. import java.util.Map;
  9. /**
  10. * shiro配置类
  11. */
  12. @Configuration
  13. public class ShiroConfig {
  14. /**
  15. * 配置安全管理器
  16. * @param userRealm UserRealm
  17. * @return DefaultWebSecurityManager
  18. */
  19. @Bean
  20. public DefaultWebSecurityManager securityManager(UserRealm userRealm) {
  21. DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
  22. securityManager.setRealm(userRealm);
  23. return securityManager;
  24. }
  25. /**
  26. * 配置Shiro过滤器工厂
  27. * @param securityManager 安全管理器
  28. * @return ShiroFilterFactoryBean
  29. */
  30. @Bean
  31. public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
  32. ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
  33. // 注册安全管理器
  34. shiroFilterFactoryBean.setSecurityManager(securityManager);
  35. /*
  36. * 设置登录页面的地址
  37. * 当用户访问认证资源的时候,如果用户没有登录,那么就会跳转到指定的页面
  38. */
  39. shiroFilterFactoryBean.setLoginUrl("/login.html");
  40. // 定义资源访问规则
  41. Map<String, String> map = new LinkedHashMap<>();
  42. /*
  43. * 过滤器说明
  44. * anon:不需要认证就可以访问的资源
  45. * authc:需要登录认证才能访问的资源
  46. */
  47. map.put("/html/home.html", "authc");
  48. // 不需要认证就能访问
  49. map.put("/login.html", "anon");
  50. map.put("/user/login", "anon");
  51. shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
  52. return shiroFilterFactoryBean;
  53. }
  54. }

当我们访问localhost:8080/login.html时,输入mumu/mhxy1218,点击登录时,会跳转到/html/home.html。

然后我们清空浏览器缓存,刷新页面,发现页面重定向回了login.html。这是因为在shiro配置类里配置了/html/home.html要身份认证之后才能访问。

map.put("/html/home.html", "authc");

第十步:实现授权功能

接下来,讲解如何通过shiro完成授权,在UserRealm里的doGetAuthorizationInfo()方法中实现授权的代码,查询用户的权限保存到shiro中,为了方便演示效果,我们模拟几条数据。

UserRealm.java

完成doGetAuthorizationInfo()方法的具体实现

  1. package cn.edu.sgu.www.shiro.realm;
  2. import cn.edu.sgu.www.shiro.entity.User;
  3. import cn.edu.sgu.www.shiro.exception.GlobalException;
  4. import cn.edu.sgu.www.shiro.mapper.UserMapper;
  5. import cn.edu.sgu.www.shiro.restful.ResponseCode;
  6. import org.apache.shiro.authc.AuthenticationInfo;
  7. import org.apache.shiro.authc.AuthenticationToken;
  8. import org.apache.shiro.authc.SimpleAuthenticationInfo;
  9. import org.apache.shiro.authc.UsernamePasswordToken;
  10. import org.apache.shiro.authz.AuthorizationInfo;
  11. import org.apache.shiro.authz.SimpleAuthorizationInfo;
  12. import org.apache.shiro.realm.AuthorizingRealm;
  13. import org.apache.shiro.subject.PrincipalCollection;
  14. import org.springframework.beans.factory.annotation.Autowired;
  15. import org.springframework.stereotype.Component;
  16. import java.util.HashSet;
  17. import java.util.Set;
  18. /**
  19. * @author heyunlin
  20. * @version 1.0
  21. */
  22. @Component
  23. public class UserRealm extends AuthorizingRealm {
  24. private final UserMapper userMapper;
  25. @Autowired
  26. public UserRealm(UserMapper userMapper) {
  27. this.userMapper = userMapper;
  28. }
  29. /**
  30. * 认证
  31. */
  32. @Override
  33. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
  34. UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
  35. // 得到用户名
  36. String username = token.getUsername();
  37. // 根据用户名查询用户信息
  38. User user = userMapper.selectByUsername(username);
  39. if (user == null) {
  40. throw new GlobalException(ResponseCode.BAD_REQUEST, "登录失败,用户不存在~");
  41. }
  42. if (user.getIsEnable()) {
  43. String password = new String(token.getPassword());
  44. if (user.getPassword().equals(password)) {
  45. return new SimpleAuthenticationInfo(user, password, username);
  46. } else {
  47. throw new GlobalException(ResponseCode.BAD_REQUEST, "用户名或密码错误,登录失败!");
  48. }
  49. }
  50. return null;
  51. }
  52. /**
  53. * 授权
  54. */
  55. @Override
  56. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
  57. SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
  58. Set<String> permissions = new HashSet<>();
  59. permissions.add("/user/delete");
  60. permissions.add("/user/update");
  61. authorizationInfo.setStringPermissions(permissions);
  62. return authorizationInfo;
  63. }
  64. }

UserController.java

在UserController中添加两个方法delete()和update()

  1. package cn.edu.sgu.www.shiro.controller;
  2. import cn.edu.sgu.www.shiro.dto.UserLoginDTO;
  3. import cn.edu.sgu.www.shiro.restful.JsonResult;
  4. import cn.edu.sgu.www.shiro.service.UserService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.bind.annotation.RequestMethod;
  8. import org.springframework.web.bind.annotation.RestController;
  9. /**
  10. * @author heyunlin
  11. * @version 1.0
  12. */
  13. @RestController
  14. @RequestMapping(path = "/user", produces = "application/json;charset=utf-8")
  15. public class UserController {
  16. private final UserService userService;
  17. @Autowired
  18. public UserController(UserService userService) {
  19. this.userService = userService;
  20. }
  21. @RequestMapping(path = "/login", method = RequestMethod.POST)
  22. public JsonResult<Void> login(UserLoginDTO loginDTO) {
  23. userService.login(loginDTO);
  24. return JsonResult.success();
  25. }
  26. @RequestMapping(path = "/delete", method = RequestMethod.POST)
  27. public JsonResult<Void> delete() {
  28. return JsonResult.success("删除成功");
  29. }
  30. @RequestMapping(path = "/update", method = RequestMethod.POST)
  31. public JsonResult<Void> update() {
  32. return JsonResult.success("修改成功");
  33. }
  34. }

/html/home.html 

home.html中新增两个按钮,同时还有引入jquery。

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8" />
  5. <title>系统首页</title>
  6. <script src="/js/jquery.min.js"></script>
  7. </head>
  8. <body>
  9. <h1>欢迎来到系统首页!</h1>
  10. <button type="button" id="delete">删除</button> | <button type="button" id="update">修改</button>
  11. <script>
  12. $(function () {
  13. $("#delete").click(function () {
  14. $.post("/user/delete", function (resp) {
  15. alert(resp.message);
  16. });
  17. });
  18. $("#update").click(function () {
  19. $.post("/user/update", function (resp) {
  20. alert(resp.message);
  21. });
  22. });
  23. });
  24. </script>
  25. </body>
  26. </html>

自定义过滤器实现鉴权

自定义过滤器AuthorizationFilter实现鉴权功能。

  1. package cn.edu.sgu.www.shiro.filter;
  2. import cn.edu.sgu.www.shiro.restful.JsonResult;
  3. import cn.edu.sgu.www.shiro.restful.ResponseCode;
  4. import com.alibaba.fastjson.JSON;
  5. import org.apache.shiro.SecurityUtils;
  6. import org.apache.shiro.subject.Subject;
  7. import javax.servlet.*;
  8. import javax.servlet.annotation.WebFilter;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;
  11. import java.io.IOException;
  12. /**
  13. * 鉴权过滤器
  14. * @author heyunlin
  15. * @version 1.0
  16. */
  17. @WebFilter
  18. public class AuthorizationFilter implements Filter {
  19. @Override
  20. public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
  21. HttpServletRequest request = (HttpServletRequest) req;
  22. String requestURI = request.getRequestURI();
  23. Subject subject = SecurityUtils.getSubject();
  24. if (subject != null && !subject.isPermitted(requestURI)) {
  25. HttpServletResponse response = (HttpServletResponse) resp;
  26. response.setContentType("application/json;charset=utf-8");
  27. // 构建返回对象
  28. JsonResult<Void> jsonResult= JsonResult.error(ResponseCode.UNAUTHORIZED, "正在访问未授权的资源");
  29. String data = JSON.toJSONString(jsonResult);
  30. response.getWriter().write(data);
  31. return;
  32. }
  33. chain.doFilter(req, resp);
  34. }
  35. }

ShiroConfig.java

把自定义过滤器加入到shiro的过滤器链中,处理删除和修改两个接口。

map.put("/user/delete", "authorization");
map.put("/user/update", "authorization");

  1. package cn.edu.sgu.www.shiro.config;
  2. import cn.edu.sgu.www.shiro.filter.AuthorizationFilter;
  3. import cn.edu.sgu.www.shiro.realm.UserRealm;
  4. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
  5. import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.context.annotation.Configuration;
  8. import javax.servlet.Filter;
  9. import java.util.LinkedHashMap;
  10. import java.util.Map;
  11. /**
  12. * shiro配置类
  13. */
  14. @Configuration
  15. public class ShiroConfig {
  16. /**
  17. * 配置安全管理器
  18. * @param userRealm UserRealm
  19. * @return DefaultWebSecurityManager
  20. */
  21. @Bean
  22. public DefaultWebSecurityManager securityManager(UserRealm userRealm) {
  23. DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
  24. securityManager.setRealm(userRealm);
  25. return securityManager;
  26. }
  27. /**
  28. * 配置Shiro过滤器工厂
  29. * @param securityManager 安全管理器
  30. * @return ShiroFilterFactoryBean
  31. */
  32. @Bean
  33. public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
  34. ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
  35. // 注册安全管理器
  36. shiroFilterFactoryBean.setSecurityManager(securityManager);
  37. /*
  38. * 设置登录页面的地址
  39. * 当用户访问认证资源的时候,如果用户没有登录,那么就会跳转到指定的页面
  40. */
  41. shiroFilterFactoryBean.setLoginUrl("/login.html");
  42. // 定义资源访问规则
  43. Map<String, String> map = new LinkedHashMap<>();
  44. /*
  45. * 过滤器说明
  46. * anon:不需要认证就可以访问的资源
  47. * authc:需要登录认证才能访问的资源
  48. */
  49. map.put("/html/home.html", "authc");
  50. // 不需要认证就能访问
  51. map.put("/login.html", "anon");
  52. map.put("/user/login", "anon");
  53. // 设置自定义过滤器
  54. map.put("/user/delete", "authorization");
  55. map.put("/user/update", "authorization");
  56. shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
  57. Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();
  58. filters.put("authorization", new AuthorizationFilter());
  59. shiroFilterFactoryBean.setFilters(filters);
  60. shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
  61. return shiroFilterFactoryBean;
  62. }
  63. }

第十一步:测试鉴权功能

为了测试,注释掉修改接口的资源权限,然后重启一下项目。

点击删除按钮会提升删除成功,但是修改的时候提示未授权。

好了,文章就分享到这里了,如果看完这篇文章感觉对你有所帮助,不要忘了点赞+收藏哦~

代码已经上传到git仓库,可按需获取:

springboot整合shiro实现认证和授权功能icon-default.png?t=N7T8https://gitee.com/he-yunlin/springboot-shiro.git

更多代码详情,请参考博主的另一篇文章:

springboot整合shiro实现动态认证和授权icon-default.png?t=N7T8https://blog.csdn.net/heyl163_/article/details/131518274

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/774478
推荐阅读
相关标签
  

闽ICP备14008679号