Shiro--整合jwt--通过url路径控制权限--使用/教程/实例

以你之姓@ 2022-09-14 00:12 395阅读 0赞

原文网址:Shiro—整合jwt—通过url路径控制权限—使用/教程/实例_IT利刃出鞘的博客-CSDN博客

简介

说明

本文用实例介绍shiro的使用。采用jwt+url权限的方式控制权限。

  1. 使用jwt替代默认的authc作为认证方式,通过url路径控制授权。
  2. 其他尽量使用原生的shiro配置,尽量少自定义配置。

我自己自测通过,代码可用。

关联文章

本文是在此文章基础上进行修改,修改点如下:

  • 数据库

    • t_permission表的name字段改为url字段
    • t_permission相应的插入的数据发生变化
  • Mapper

    • PermissionMapper

      • 原先:返回t_permission.name字段
      • 本文:返回t_permission.url字段
  • Controller

    • 原先:使用@RequiresPermissions、@RequiresRoles控制权限
    • 本文:去掉这两个注解,通过url控制权限
  • Shiro配置

    • 注册授权过滤器(url路径过滤器)

      • 提供url路径过滤器(UrlFiter类)
      • 将url路径过滤器注册进去(ShiroConfig#shiroFilterFactoryBean)
    • 修改认证过滤器(JwtFilter)

      • 原先:只需通过返回true或者executeLogin即可
      • 本文:自定义响应数据。(若不这么写,响应数据会很不友好,因为我们已经不是shiro的标准用法了)

除了上述修改之外,其他的代码、逻辑一点都没变。

修改点数据库

  1. DROP DATABASE IF EXISTS shiro;
  2. CREATE DATABASE shiro DEFAULT CHARACTER SET utf8;
  3. USE shiro;
  4. DROP TABLE IF EXISTS t_user;
  5. DROP TABLE IF EXISTS t_role;
  6. DROP TABLE IF EXISTS t_permission;
  7. DROP TABLE IF EXISTS t_user_role_mid;
  8. DROP TABLE IF EXISTS t_role_permission_mid;
  9. CREATE TABLE t_user (
  10. id bigint AUTO_INCREMENT,
  11. user_name VARCHAR(100),
  12. password VARCHAR(100),
  13. salt VARCHAR(100),
  14. PRIMARY KEY(id)
  15. ) charset=utf8 ENGINE=InnoDB;
  16. CREATE TABLE t_role (
  17. id bigint AUTO_INCREMENT,
  18. name VARCHAR(100),
  19. description VARCHAR(100),
  20. PRIMARY KEY(id)
  21. ) charset=utf8 ENGINE=InnoDB;
  22. CREATE TABLE t_permission (
  23. id bigint AUTO_INCREMENT,
  24. url VARCHAR(100),
  25. description VARCHAR(100),
  26. PRIMARY KEY(id)
  27. ) charset=utf8 ENGINE=InnoDB;
  28. CREATE TABLE t_user_role_mid (
  29. id bigint AUTO_INCREMENT,
  30. user_id bigint,
  31. role_id bigint,
  32. PRIMARY KEY(id)
  33. ) charset=utf8 ENGINE=InnoDB;
  34. CREATE TABLE t_role_permission_mid (
  35. id bigint AUTO_INCREMENT,
  36. role_id bigint,
  37. permission_id bigint,
  38. PRIMARY KEY(id)
  39. ) charset=utf8 ENGINE=InnoDB;
  40. -- 密码:12345
  41. INSERT INTO `t_user` VALUES (1,"zhang3","a7d59dfc5332749cb801f86a24f5f590","e5ykFiNwShfCXvBRPr3wXg==");
  42. -- 密码:abcde
  43. INSERT INTO `t_user` VALUES (2,"li4","43e28304197b9216e45ab1ce8dac831b","jPz19y7arvYIGhuUjsb6sQ==");
  44. INSERT INTO `t_role` VALUES (1,"admin","超级管理员");
  45. INSERT INTO `t_role` VALUES (2,"productManager","产品管理员");
  46. INSERT INTO `t_role` VALUES (3,"orderManager","订单管理员");
  47. INSERT INTO `t_permission` VALUES (1,"/product/add","增加产品");
  48. INSERT INTO `t_permission` VALUES (2,"/product/delete","删除产品");
  49. INSERT INTO `t_permission` VALUES (3,"/product/edit","编辑产品");
  50. INSERT INTO `t_permission` VALUES (4,"/product/view","查看产品");
  51. INSERT INTO `t_permission` VALUES (5,"/order/add","增加订单");
  52. INSERT INTO `t_permission` VALUES (6,"/order/delete","删除订单");
  53. INSERT INTO `t_permission` VALUES (7,"/order/edit","编辑订单");
  54. INSERT INTO `t_permission` VALUES (8,"/order/view","查看订单");
  55. INSERT INTO `t_user_role_mid` VALUES (1,2,2);
  56. INSERT INTO `t_user_role_mid` VALUES (2,1,1);
  57. INSERT INTO `t_role_permission_mid` VALUES (1,1,1);
  58. INSERT INTO `t_role_permission_mid` VALUES (2,1,2);
  59. INSERT INTO `t_role_permission_mid` VALUES (3,1,3);
  60. INSERT INTO `t_role_permission_mid` VALUES (4,1,4);
  61. INSERT INTO `t_role_permission_mid` VALUES (5,1,5);
  62. INSERT INTO `t_role_permission_mid` VALUES (6,1,6);
  63. INSERT INTO `t_role_permission_mid` VALUES (7,1,7);
  64. INSERT INTO `t_role_permission_mid` VALUES (8,1,8);
  65. INSERT INTO `t_role_permission_mid` VALUES (9,2,1);
  66. INSERT INTO `t_role_permission_mid` VALUES (10,2,2);
  67. INSERT INTO `t_role_permission_mid` VALUES (11,2,3);
  68. INSERT INTO `t_role_permission_mid` VALUES (12,2,4);
  69. INSERT INTO `t_role_permission_mid` VALUES (13,3,5);
  70. INSERT INTO `t_role_permission_mid` VALUES (14,3,6);
  71. INSERT INTO `t_role_permission_mid` VALUES (15,3,7);
  72. INSERT INTO `t_role_permission_mid` VALUES (16,3,8);

修改点代码

Shiro配置

添加Url过滤器(继承PathMatchingFilter)

  1. package com.example.demo.config.shiro.filter;
  2. import com.example.demo.common.entity.Result;
  3. import com.example.demo.common.util.ApplicationContextHolder;
  4. import com.example.demo.common.util.ResponseUtil;
  5. import com.example.demo.common.util.auth.JwtUtil;
  6. import com.example.demo.rbac.permission.service.PermissionService;
  7. import com.fasterxml.jackson.databind.ObjectMapper;
  8. import lombok.extern.slf4j.Slf4j;
  9. import org.apache.shiro.web.filter.PathMatchingFilter;
  10. import org.springframework.http.HttpHeaders;
  11. import org.springframework.http.HttpStatus;
  12. import javax.servlet.ServletRequest;
  13. import javax.servlet.ServletResponse;
  14. import javax.servlet.http.HttpServletRequest;
  15. import javax.servlet.http.HttpServletResponse;
  16. import java.util.Set;
  17. @Slf4j
  18. public class UrlFilter extends PathMatchingFilter {
  19. private PermissionService permissionService;
  20. @Override
  21. protected boolean onPreHandle(ServletRequest request,
  22. ServletResponse response,
  23. Object mappedValue) throws Exception {
  24. HttpServletRequest httpServletRequest = (HttpServletRequest) request;
  25. String uri = httpServletRequest.getRequestURI();
  26. String token = httpServletRequest.getHeader(HttpHeaders.COOKIE);
  27. String userIdStr = JwtUtil.getUserIdByToken(token);
  28. Long userId = Long.parseLong(userIdStr);
  29. if (permissionService == null) {
  30. permissionService = ApplicationContextHolder.getContext().getBean(PermissionService.class);
  31. }
  32. Set<String> permissions = permissionService.getPermissionsByUserId(userId);
  33. // 实际应该从数据库或者redis里通过userId获得拥有权限的url
  34. if (permissions.contains(uri)) {
  35. return true;
  36. }
  37. // 构造无权限时的response
  38. HttpServletResponse httpResponse = (HttpServletResponse) response;
  39. ResponseUtil.jsonResponse(httpResponse, HttpStatus.FORBIDDEN.value(),
  40. "用户(" + userId + ")无此url(" + uri + ")权限");
  41. return false;
  42. }
  43. }

注册Url过滤器

  1. package com.example.demo.config.shiro;
  2. import com.example.demo.common.constant.WhiteList;
  3. import com.example.demo.config.shiro.filter.JwtFilter;
  4. import com.example.demo.config.shiro.filter.UrlFilter;
  5. import com.example.demo.config.shiro.realm.AccountRealm;
  6. import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
  7. import org.apache.shiro.mgt.DefaultSubjectDAO;
  8. import org.apache.shiro.mgt.SecurityManager;
  9. import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
  10. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
  11. import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
  12. import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
  13. import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
  14. import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
  15. import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
  16. import org.springframework.context.annotation.Bean;
  17. import org.springframework.context.annotation.Configuration;
  18. import org.springframework.context.annotation.Lazy;
  19. import javax.servlet.Filter;
  20. import java.util.LinkedHashMap;
  21. import java.util.Map;
  22. @Configuration
  23. public class ShiroConfig {
  24. @Lazy
  25. @Bean("shiroFilterFactoryBean")
  26. public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
  27. ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
  28. shiroFilterFactoryBean.setSecurityManager(securityManager);
  29. // 如果实现了AuthenticatingFilter.java要设置下边这个,因为shiro很多地方依据loginUrl进行判断
  30. // shiroFilterFactoryBean.setLoginUrl("/login");
  31. // // 登录成功后要跳转的链接
  32. // shiroFilterFactoryBean.setSuccessUrl("/index");
  33. // // 未授权界面;
  34. // shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
  35. Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
  36. WhiteList.ALL.forEach(str -> {
  37. filterChainDefinitionMap.put(str, "anon");
  38. });
  39. filterChainDefinitionMap.put("/login", "anon");
  40. filterChainDefinitionMap.put("/logout", "jwtAuthc");
  41. // 下边这行不要打开。原因待确定
  42. // filterChainDefinitionMap.put("/logout", "logout");
  43. filterChainDefinitionMap.put("/**", "jwtAuthc,urlAuthz");
  44. Map<String, Filter> customisedFilters = new LinkedHashMap<>();
  45. //不能通过注入来设置过滤器。如果通过注入,则本过滤器优先级会最高(/**优先级最高,导致前边所有请求都无效)。
  46. // springboot会扫描所有实现了javax.servlet.Filter接口的类,无需加@Component也会扫描到。
  47. customisedFilters.put("jwtAuthc", new JwtFilter());
  48. customisedFilters.put("urlAuthz", new UrlFilter());
  49. shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
  50. shiroFilterFactoryBean.setFilters(customisedFilters);
  51. return shiroFilterFactoryBean;
  52. }
  53. @Bean
  54. public DefaultWebSecurityManager securityManager() {
  55. DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
  56. DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
  57. // 关闭shiro自带的session。这样不能通过session登录shiro,后面将采用jwt凭证登录。
  58. // 见:http://shiro.apache.org/session-management.html#SessionManagement-DisablingSubjectStateSessionStorage
  59. defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
  60. subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
  61. DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
  62. securityManager.setRealm(getDatabaseRealm());
  63. securityManager.setSubjectDAO(subjectDAO);
  64. return securityManager;
  65. }
  66. @Bean
  67. public AccountRealm getDatabaseRealm() {
  68. return new AccountRealm();
  69. }
  70. /**
  71. * setUsePrefix(true)用于解决一个奇怪的bug。如下:
  72. * 在引入spring aop的情况下,在@Controller注解的类的方法中加入@RequiresRole等
  73. * shiro注解,会导致该方法无法映射请求,导致返回404。加入这项配置能解决这个bug。
  74. */
  75. @Bean
  76. public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
  77. DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
  78. defaultAdvisorAutoProxyCreator.setUsePrefix(true);
  79. return defaultAdvisorAutoProxyCreator;
  80. }
  81. /**
  82. * 开启shiro 注解。比如:@RequiresRole
  83. * 本处不用此方法开启注解,使用引入spring aop依赖的方式。原因见:application.yml里的注释
  84. */
  85. /*@Bean
  86. public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
  87. SecurityManager securityManager) {
  88. AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
  89. new AuthorizationAttributeSourceAdvisor();
  90. authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
  91. return authorizationAttributeSourceAdvisor;
  92. }*/
  93. }

修改JwtFilter

  1. package com.example.demo.config.shiro.filter;
  2. import com.example.demo.common.util.ResponseUtil;
  3. import com.example.demo.common.util.auth.JwtUtil;
  4. import com.example.demo.config.shiro.entity.JwtToken;
  5. import org.apache.shiro.authc.AuthenticationToken;
  6. import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
  7. import org.springframework.http.HttpHeaders;
  8. import org.springframework.http.HttpStatus;
  9. import org.springframework.util.StringUtils;
  10. import javax.servlet.ServletRequest;
  11. import javax.servlet.ServletResponse;
  12. import javax.servlet.http.HttpServletRequest;
  13. import javax.servlet.http.HttpServletResponse;
  14. public class JwtFilter extends AuthenticatingFilter {
  15. /**
  16. * 所有请求都会到这里来(无论是不是anon)。
  17. * 返回true:表示允许向下走。后边会走PathMatchingFilter,看路径是否对应anon等
  18. * 返回false:表示不允许向下走。
  19. */
  20. @Override
  21. protected boolean onAccessDenied(ServletRequest servletRequest,
  22. ServletResponse servletResponse) throws Exception {
  23. HttpServletRequest request = (HttpServletRequest) servletRequest;
  24. String token = request.getHeader(HttpHeaders.COOKIE);
  25. // 自定义Header也可以,但浏览器不会存自定义的Header,需要前端自己去存
  26. // String token = request.getHeader("Authentication");
  27. if (!StringUtils.hasText(token)) {
  28. return true;
  29. } else {
  30. boolean verified = JwtUtil.verifyToken(token);
  31. if (!verified) {
  32. HttpServletResponse response = (HttpServletResponse) servletResponse;
  33. ResponseUtil.jsonResponse(response, HttpStatus.UNAUTHORIZED.value(), "认证失败");
  34. return false;
  35. }
  36. }
  37. // 此登录并非调用login接口,而是shiro层面的登录。
  38. // 里边会调用下边的createToken方法
  39. return executeLogin(servletRequest, servletResponse);
  40. }
  41. /**
  42. * 这里的token会传给AuthorizingRealm子类(本处是AccountRealm)的doGetAuthenticationInfo方法作为参数
  43. */
  44. @Override
  45. protected AuthenticationToken createToken(ServletRequest servletRequest,
  46. ServletResponse servletResponse) {
  47. HttpServletRequest request = (HttpServletRequest) servletRequest;
  48. String token = request.getHeader(HttpHeaders.COOKIE);
  49. // 自定义Header也可以,但浏览器不会存自定义的Header,需要前端自己去存
  50. // String token = request.getHeader("Authentication");
  51. if (!StringUtils.hasText(token)) {
  52. return null;
  53. }
  54. return new JwtToken(token);
  55. }
  56. }

工具类ResponseUtil

  1. package com.example.demo.common.util;
  2. import com.example.demo.common.entity.Result;
  3. import com.fasterxml.jackson.databind.ObjectMapper;
  4. import org.springframework.http.HttpStatus;
  5. import javax.servlet.http.HttpServletResponse;
  6. public class ResponseUtil {
  7. public static void jsonResponse(HttpServletResponse response, int status, String message) throws Exception {
  8. //让浏览器用utf8来解析返回的数据
  9. response.setHeader("Content-type", "application/json;charset=UTF-8");
  10. //告诉servlet用UTF-8转码,而不是用默认的ISO8859
  11. response.setCharacterEncoding("UTF-8");
  12. response.setStatus(status);
  13. Result result = new Result().failure().message(message);
  14. String json = new ObjectMapper().writeValueAsString(result);
  15. response.getWriter().print(json);
  16. }
  17. }

Mapper

修改SQL

  1. package com.example.demo.rbac.permission.mapper;
  2. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  3. import com.example.demo.rbac.permission.entity.Permission;
  4. import org.apache.ibatis.annotations.Param;
  5. import org.apache.ibatis.annotations.Select;
  6. import org.springframework.stereotype.Repository;
  7. import java.util.Set;
  8. @Repository
  9. public interface PermissionMapper extends BaseMapper<Permission> {
  10. @Select("SELECT " +
  11. " t_permission.`url` " +
  12. "FROM " +
  13. " t_user, " +
  14. " t_user_role_mid, " +
  15. " t_role, " +
  16. " t_role_permission_mid, " +
  17. " t_permission " +
  18. "WHERE " +
  19. " t_user.`id` = #{userId} " +
  20. " AND t_user.id = t_user_role_mid.user_id " +
  21. " AND t_user_role_mid.role_id = t_role.id " +
  22. " AND t_role.id = t_role_permission_mid.role_id " +
  23. " AND t_role_permission_mid.permission_id = t_permission.id")
  24. Set<String> getPermissionsByUserId(@Param("userId") Long userId);
  25. }

Controller

产品

  1. package com.example.demo.business.product;
  2. import com.example.demo.common.entity.Result;
  3. import io.swagger.annotations.Api;
  4. import io.swagger.annotations.ApiOperation;
  5. import org.apache.shiro.authz.annotation.RequiresPermissions;
  6. import org.springframework.web.bind.annotation.GetMapping;
  7. import org.springframework.web.bind.annotation.PostMapping;
  8. import org.springframework.web.bind.annotation.RequestMapping;
  9. import org.springframework.web.bind.annotation.RestController;
  10. @Api(tags = "产品")
  11. @RestController
  12. @RequestMapping("product")
  13. public class ProductController {
  14. @ApiOperation(value="增加产品")
  15. @PostMapping("add")
  16. public Result add() {
  17. return new Result<>().message("product:add success");
  18. }
  19. @ApiOperation(value="删除产品")
  20. @PostMapping("delete")
  21. public Result delete() {
  22. return new Result<>().message("product:delete success");
  23. }
  24. @ApiOperation(value="编辑产品")
  25. @PostMapping("edit")
  26. public Result edit() {
  27. return new Result<>().message("product:edit success");
  28. }
  29. @ApiOperation(value="查看产品")
  30. @GetMapping("view")
  31. public Result view() {
  32. return new Result<>().message("product:view success");
  33. }
  34. }

订单

  1. package com.example.demo.business.order;
  2. import com.example.demo.common.entity.Result;
  3. import io.swagger.annotations.Api;
  4. import io.swagger.annotations.ApiOperation;
  5. import org.apache.shiro.authz.annotation.Logical;
  6. import org.apache.shiro.authz.annotation.RequiresPermissions;
  7. import org.apache.shiro.authz.annotation.RequiresRoles;
  8. import org.springframework.web.bind.annotation.GetMapping;
  9. import org.springframework.web.bind.annotation.PostMapping;
  10. import org.springframework.web.bind.annotation.RequestMapping;
  11. import org.springframework.web.bind.annotation.RestController;
  12. @Api(tags = "订单")
  13. @RestController
  14. @RequestMapping("order")
  15. public class OrderController {
  16. @ApiOperation(value="增加订单")
  17. @PostMapping("add")
  18. public Result add() {
  19. return new Result<>().message("order:add success");
  20. }
  21. @ApiOperation(value="删除订单")
  22. @PostMapping("delete")
  23. public Result delete() {
  24. return new Result<>().message("order:delete success");
  25. }
  26. @ApiOperation(value="编辑订单")
  27. @PostMapping("edit")
  28. public Result edit() {
  29. return new Result<>().message("order:edit success");
  30. }
  31. @ApiOperation(value="查看订单")
  32. @GetMapping("view")
  33. public Result view() {
  34. return new Result<>().message("order:view success");
  35. }
  36. }

测试

测试超级管理员(admin)

启动项目,访问:http://localhost:8080/doc.html

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBASVTliKnliIPlh7rpnpg_size_20_color_FFFFFF_t_70_g_se_x_16

1.测试登录

  1. 登录成功
  2. 可以看到,会返回来一个Set-Cookie头,值是token。

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBASVTliKnliIPlh7rpnpg_size_20_color_FFFFFF_t_70_g_se_x_16 1

2.测试有资源权限的接口

本处测试增加产品接口。

  1. 成功访问。
  2. 在请求时会传递Cookie

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBASVTliKnliIPlh7rpnpg_size_20_color_FFFFFF_t_70_g_se_x_16 2

我使用标准的:Set-Cookie,Cookie来做认证的。若是自定义的header,需要手动写入:

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBASVTliKnliIPlh7rpnpg_size_20_color_FFFFFF_t_70_g_se_x_16 3

3.测试登出

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBASVTliKnliIPlh7rpnpg_size_20_color_FFFFFF_t_70_g_se_x_16 4

4.再次访问接口

  1. 访问成功。
  2. 因为token还没过期,浏览器也还会将其发给服务端,所以成功。

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBASVTliKnliIPlh7rpnpg_size_20_color_FFFFFF_t_70_g_se_x_16 5

测试产品管理员(productManager)

启动项目,访问:http://localhost:8080/doc.html

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBASVTliKnliIPlh7rpnpg_size_20_color_FFFFFF_t_70_g_se_x_16 6

1.测试登录

  1. 登录成功
  2. 可以看到,会返回来一个Set-Cookie头,值是token。

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBASVTliKnliIPlh7rpnpg_size_20_color_FFFFFF_t_70_g_se_x_16 7

2.测试有资源权限的接口

本处测试增加产品接口。

  1. 成功访问。
  2. 在请求时会传递Cookie

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBASVTliKnliIPlh7rpnpg_size_20_color_FFFFFF_t_70_g_se_x_16 8

3.测试无资源权限的接口

本处测试增加订单接口。

  1. 访问失败。
  2. 在请求时会传递Cookie
  3. 有一处细节:提示是红色的。

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBASVTliKnliIPlh7rpnpg_size_20_color_FFFFFF_t_70_g_se_x_16 9

点进去看,可以看到状态码是我指定的:403

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBASVTliKnliIPlh7rpnpg_size_20_color_FFFFFF_t_70_g_se_x_16 10

重启服务再请求

1.登录

登录成功

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBASVTliKnliIPlh7rpnpg_size_20_color_FFFFFF_t_70_g_se_x_16 11

2.重启服务器

重启Idea启动的应用。

3.访问有权限的接口

本处访问产品增加接口。

  1. 可以看到,访问成功。

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBASVTliKnliIPlh7rpnpg_size_20_color_FFFFFF_t_70_g_se_x_16 12

超时后再请求

1.修改配置文件,暂时将token过期时间改短(本处改为10秒)

application.yml

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBASVTliKnliIPlh7rpnpg_size_20_color_FFFFFF_t_70_g_se_x_16 13

2.登录

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBASVTliKnliIPlh7rpnpg_size_20_color_FFFFFF_t_70_g_se_x_16 14

3.等待大于10秒之后再请求

请求失败。

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBASVTliKnliIPlh7rpnpg_size_20_color_FFFFFF_t_70_g_se_x_16 15

我代码里指定这种错误为401,点进去验证下:

watermark_type_ZHJvaWRzYW5zZmFsbGJhY2s_shadow_50_text_Q1NETiBASVTliKnliIPlh7rpnpg_size_20_color_FFFFFF_t_70_g_se_x_16 16

其他网址

Shiro实例系列

Shiro—SpringBoot—Session—使用/用法/实例/示例_IT利刃出鞘的博客-CSDN博客
Shiro—SpringBoot—shiro-redis—使用/用法/实例/示例_IT利刃出鞘的博客-CSDN博客
Shiro—SpringBoot—jwt—使用/用法/实例/示例_IT利刃出鞘的博客-CSDN博客
Shiro—SpringBoot—jwt—url路径(PathMatchingFilter)/通过url路径控制权限—使用/用法/实例/示例_IT利刃出鞘的博客-CSDN博客

发表评论

表情:
评论列表 (有 0 条评论,395人围观)

还没有评论,来说两句吧...

相关阅读