# shiro学习
**Repository Path**: wangzhaoyv/shiro_learning
## Basic Information
- **Project Name**: shiro学习
- **Description**: shrio学习项目
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-04-16
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## 代码改变位置
``` xml
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.2.6.RELEASE
com.wzy
shiro-study
0.0.1-SNAPSHOT
shiro-study
Demo project for Spring Boot
1.8
mysql
mysql-connector-java
8.0.19
com.alibaba
druid-spring-boot-starter
1.1.10
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-devtools
runtime
true
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
com.baomidou
mybatis-plus-boot-starter
3.3.1.tmp
com.baomidou
mybatis-plus-generator
3.3.1.tmp
org.apache.velocity
velocity-engine-core
2.2
com.google.guava
guava
23.0
org.apache.shiro
shiro-spring
1.3.2
com.auth0
java-jwt
3.2.0
org.springframework.boot
spring-boot-maven-plugin
```
## 图片说明

### JWTUtil.java
```java
package com.wzy.shirostudy.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.JWTVerifier;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.UnsupportedEncodingException;
import java.util.Date;
/**
* @program: shiro-study
* @description: JWT工具
* @author: 1
* @create: 2020-04-16 22:21
**/
public class JWTUtil {
final static Logger logger = LogManager.getLogger(JWTUtil.class);
/**
* 过期时间30分钟
*/
private static final long EXPIRE_TIME = 30 * 60 * 1000;
/**
* 校验token是否正确
*
* @param token 密钥
* @param secret 用户的密码
* @return 是否正确
*/
public static boolean verify(String token,String username,Integer userId, String secret) {
try {
String id = String.valueOf(userId);
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm)
.withClaim("userId", id)
.withClaim("username", username)
.build();
verifier.verify(token);
return true;
} catch (Exception exception) {
return false;
}
}
/**
* 获得token中的信息无需secret解密也能获得
*
* @return token中包含的用户名
*/
public static String getUsername(String token) {
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("username").asString();
} catch (JWTDecodeException e) {
return null;
}
}
/**
* 获得token中的信息无需secret解密也能获得
*
* @return token中包含的用户id
*/
public static Integer getUserId(String token) {
try {
DecodedJWT jwt = JWT.decode(token);
return Integer.valueOf(jwt.getClaim("userId").asString());
} catch (JWTDecodeException e) {
return null;
}
}
/**
* 生成签名,30min后过期
*
* @param username 用户名
* @param secret 用户的密码
* @return 加密的token
*/
public static String sign(Integer userId ,String username, String secret) {
try {
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
//使用用户自己的密码充当加密密钥
Algorithm algorithm = null;
algorithm = Algorithm.HMAC256(secret);
// 附带userId信息 注意这个是必须要变为string类型后才可以放入构造者里去,否则后面无法取到值,存入userId也是因为我数据表中,userId比username有用
String id = String.valueOf(userId);
// 建造者模式
String jwtString = JWT.create()
.withClaim("userId", id)
.withClaim("username", username)
.withExpiresAt(date)
.sign(algorithm);
logger.debug(String.format("JWT:%s", jwtString));
return jwtString;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
}
```
## JwtToken.java
```java
package com.wzy.shirostudy.jwt;
import org.apache.shiro.authc.AuthenticationToken;
/**
* @program: shiro-study
* @description: 存取用户名及密码
* @author: 1
* @create: 2020-04-16 16:39
**/
public class JwtToken implements AuthenticationToken {
/**
* 密钥
*/
private String token;
public JwtToken(String token) {
this.token = token;
}
@Override
public Object getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
}
```
### ShrioCustomRealm.java
```java
package com.wzy.shirostudy.configurer;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wzy.shirostudy.domain.SysPermission;
import com.wzy.shirostudy.domain.SysRole;
import com.wzy.shirostudy.domain.SysUser;
import com.wzy.shirostudy.jwt.JwtToken;
import com.wzy.shirostudy.service.SysPermissionService;
import com.wzy.shirostudy.service.SysRoleService;
import com.wzy.shirostudy.service.SysUserService;
import com.wzy.shirostudy.utils.JWTUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import com.google.common.collect.Sets;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
/**
* @program: shiro-study
* @description: 权限认证
* @author: 1
* @create: 2020-04-15 18:15
**/
@Slf4j
@Configuration
public class ShiroCustomRealm extends AuthorizingRealm {
@Resource
private SysUserService sysUserServiceImpl;
@Resource
private SysRoleService sysRoleServiceImpl;
@Resource
private SysPermissionService sysPermissionServiceImpl;
/**
* 必须重写此方法,不然Shiro会报错
*/
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JwtToken;
}
/**
* 对用户进行授权 第一次请求的时候就会启动该方法
* 注意:这里我在生成token的时候放入了userId所以这里才可以取userId
* 获取权限这里基本没有改变,就是这里获取的是token 然后解密提取其中的userId
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String token = (String) SecurityUtils.getSubject().getPrincipal();
Integer userId = JWTUtil.getUserId(token);
log.info("--------获取权限---------- : " + token);
/**
* 获取用户的角色列表
*/
Set roles = Sets.newHashSet();
List roleList = sysRoleServiceImpl.getRoleByUserId(userId);
roleList.forEach(role -> {
roles.add(role.getName());
});
//设置用户角色
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
// 获得该用户角色权限列表
List permissionList = sysPermissionServiceImpl.getPermissionListByUserId(userId);
Set permissions = Sets.newHashSet();
permissionList.forEach(permission -> {
if (permission.getPermission() != null && !"".equals(permission.getPermission()) {
permissions.add(permission.getPermission());
}
});
//设置角色权限
info.setStringPermissions(permissions);
return info;
}
/**
* 获取身份验证信息
* shiro会通过 Realm 来获取应用程序中的用户,角色及权限信息
*
* 注意,这里本是Cookies版本中的登录环节,但是在jwt版本中,登录接口并不调用此处的登录
* 后面在controller里可以看到,这里拿到token后的登录
*
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String token = (String) authenticationToken.getCredentials();
// 解密获得username,用于和数据库进行对比
Integer userId = JWTUtil.getUserId(token);
//没有登录用户信息直接返回
if (userId == null) {
throw new AuthenticationException("token invalid");
}
//使用登录名获取用户信息
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("id", userId);
SysUser sysUser = sysUserServiceImpl.getOne(queryWrapper);
//如果有查询到用户信息,就将userId转存到token的username中,这样为后面获取数据提供便利
if (!JWTUtil.verify(token,sysUser.getUsername(), sysUser.getId(), sysUser.getPassword())) {
throw new AuthenticationException("Username or password error");
}
return new SimpleAuthenticationInfo(token, token, "shiro_custom_realm");
}
}
```
### JwtFilter.java
```java
package com.wzy.shirostudy.filter;
import com.wzy.shirostudy.jwt.JwtToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.AccessControlFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @url https://www.cnblogs.com/dadiwm321/p/shiro_jwt.html
* @program: shiro-study
* @description: 自定义一个Filter,用来拦截所有的请求判断是否携带Token
* isAccessAllowed()判断是否携带了有效的JwtToken
* onAccessDenied()是没有携带JwtToken的时候进行账号密码登录,登录成功允许访问,登录失败拒绝访问
* @author: 1
* @create: 2020-04-16 20:38
**/
@Slf4j
public class JwtFilter extends AccessControlFilter {
/**
* 1. 返回true,shiro就直接允许访问url
* 2. 返回false,shiro才会根据onAccessDenied的方法的返回值决定是否允许访问url
* @param request
* @param response
* @param mappedValue
* @return
* @throws Exception
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
log.warn("isAccessAllowed 方法被调用");
//这里先让它始终返回false来使用onAccessDenied()方法
return false;
}
/**
* 返回结果为true表明登录通过
* @param servletRequest
* @param servletResponse
* @return
* @throws Exception
*/
@Override
protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
log.warn("------onAccessDenied 方法被调用");
//这个地方和前端约定,要求前端将jwtToken放在请求的Header部分
//所以以后发起请求的时候就需要在Header中放一个Authorization,值就是对应的Token
HttpServletRequest request = (HttpServletRequest) servletRequest;
String jwt = request.getHeader("Authorization");
JwtToken jwtToken = new JwtToken(jwt);
/*
* 下面就是固定写法
* */
try {
// 委托 realm 进行登录认证
//所以这个地方最终还是调用JwtRealm进行的认证
getSubject(servletRequest, servletResponse).login(jwtToken);
//也就是subject.login(token)
} catch (Exception e) {
e.printStackTrace();
onLoginFail(servletResponse);
//调用下面的方法向客户端返回错误信息
return false;
}
return true;
//执行方法中没有抛出异常就表示登录成功
}
/**
* 登录失败时默认返回 401 状态码
* @param response
* @throws IOException
*/
private void onLoginFail(ServletResponse response) throws IOException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
httpResponse.getWriter().write("token 令牌失效");
}
}
```
> 原ShiroUserFilter ====> JWTFilter
>
> 原filter功能只做 : 跨域处理0
>
> 现在就要做: shiro登录认证授权
>
> 那么问题来了,跨域呢???
>
> 还记得那个废弃的filter吗?当时就是因为做了跨域,始终都进不了登录验证,可能是我写的有问题,不过跨域问题先放一下吧!
>
> 可能是我没有用return super.preHandle(request, response);这个返回,直接返回true,但是这里返回这个就报错,而且这个就是个boolean值,应该不影响的,唉!无奈
## ShrioConfig.java
```java
package com.wzy.shirostudy.configurer;
import com.wzy.shirostudy.exception.MyExceptionResolver;
import com.wzy.shirostudy.filter.JwtFilter;
import com.wzy.shirostudy.filter.JwtFilterNo;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
/**
* @program: shiro-study
* @description: shiro的配置文件
* @author: 1
* @create: 2020-04-15 16:01
**/
@Configuration
public class ShiroConfigurer {
/**
* 下面的代码是添加注解支持
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
// 强制使用cglib,防止重复代理和可能引起代理出错的问题
// https://zhuanlan.zhihu.com/p/29161098
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
/**
* 注入 securityManager
*/
@Bean
public DefaultWebSecurityManager securityManager(ShiroCustomRealm shiroCustomRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置realm
securityManager.setRealm(shiroCustomRealm);
/**
* 关闭shiro自带的session,详情见文档
* http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
*/
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
securityManager.setSubjectDAO(subjectDAO);
return securityManager;
}
/**
* 将shiro过滤器交给spring管理
* @param securityManager
* @return
*/
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
//加入 安全管理器 管理所有Subject 相当于整体的管理人。
factoryBean.setSecurityManager(securityManager);
/**
* 设置无权访问的地址 当使用注解时这个地址就会失效,所以需要重写异常类
* 可查看 {@link MyExceptionResolver}
*/
factoryBean.setUnauthorizedUrl("/permission/not");
// 添加自己的过滤器并且取名为jwt
Map filterMap = new HashMap<>(4);
filterMap.put("jwt", new JwtFilter());
factoryBean.setFilters(filterMap);
//基本系统级别权限配置
Map filterRuleMap = new HashMap<>();
// druid
filterRuleMap.put("/druid/**", "anon");
// 开放登陆接口
filterRuleMap.put("/user/login", "anon");
// 所有请求通过我们自己的JWT Filter 这里没有配置会导致配置
// org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported
filterRuleMap.put("/**", "jwt");
factoryBean.setFilterChainDefinitionMap(filterRuleMap);
return factoryBean;
}
}
```
> 配置文件的改变并不大,就是将jwtFilter加入到shiro的过滤器队列中
>
> 关闭shiro自带的session
> 到这里就基本结束了,尝试一下,发现并不是这么回事,咦,怎么登不上去呢!
>
> 哦,原来登录逻辑也要稍微改动一下的,在前面的Cookie版本中我们在登录时候获取了shrio的token,然后使用subject.login(token);登录,这个时候就已经走了realm的登录逻辑.
> 我们现在修改成这样子,走realm,会显示未登录(请求头没有带Authorization),所以根本走不通,所以我们放弃了以前的登录,改为新的
## SystemUserController.java
```java
package com.wzy.shirostudy.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wzy.shirostudy.domain.SysUser;
import com.wzy.shirostudy.service.SysUserService;
import com.wzy.shirostudy.utils.JWTUtil;
import com.wzy.shirostudy.utils.MD5Utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
*
* 前端控制器
*
*
* @author wzy
* @since 2020-04-16
*/
@Slf4j
@RestController
@RequestMapping("/user")
public class SysUserController {
@Resource
private SysUserService sysUserServiceImpl;
@PostMapping("/old/login")
public String userOldLogin(String username, String password) {
// 从SecurityUtils里边创建一个 subject
Subject subject = SecurityUtils.getSubject();
// 在认证提交前准备 token(令牌)
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
subject.login(token);
} catch (UnknownAccountException unknownAccountException) {
return "未知账户";
} catch (IncorrectCredentialsException incorrectCredentialsException) {
return "密码不正确";
} catch (LockedAccountException lockedAccountException) {
return "用户已锁定";
} catch (ExcessiveAttemptsException excessiveAttemptsException) {
return "用户名或密码错误次数过多";
} catch (AuthenticationException authenticationException) {
return "用户名或密码不正确";
}
if (subject.isAuthenticated()) {
return "登录成功";
} else {
token.clear();
return "登录失败";
}
}
@PostMapping("/login")
public String userLogin(String username, String password) {
log.info("用户登录");
if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
throw new RuntimeException("用户名和密码不可以为空!");
}
// 从数据库中根据用户名查找该用户信息
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("username", username);
SysUser sysUser = sysUserServiceImpl.getOne(queryWrapper);
// 登录密码加密
password = MD5Utils.md5(password);
if (null != sysUser && sysUser.getPassword().equals(password)) {
return JWTUtil.sign(sysUser.getId(),username, password);
} else {
throw new UnauthorizedException("用户名或者密码错误!");
}
}
@GetMapping("/info")
@RequiresPermissions("sys:user:query")
public String testUserInfo() {
return "恭喜获取到用户信息";
}
@GetMapping("/add")
@RequiresPermissions("sys:user:add")
public String testUserAdd() {
return "恭喜能添加用户";
}
@GetMapping("/del")
@RequiresPermissions("sys:test:del")
public String testUserDel() {
return "这是个没有权限的接口";
}
@GetMapping("/no/login")
public String testNoLogin() {
return "你没有登录";
}
}
```
> 可以看到,我们其实只是走了数据库,然后通过jwt帮我们使用userId等生成了一个token,返回给了前端,这个时候其实还没有触及到realm的验证逻辑,这个时候我们的jwt接入算是基本完成了,就剩下最后一个跨域问题没有解决了
## 最后,我们把跨域的问题解决掉
我们在新建一个CorsFilter继承BasicHttpAuthenticationFilter
## CorsFilter.java
```java
package com.wzy.shirostudy.filter;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @program: shiro-study
* @description: 跨域请求过滤器
* @author: 1
* @create: 2020-04-17 13:09
**/
@Slf4j
public class CorsFilter extends BasicHttpAuthenticationFilter {
/**
* 对跨域提供支持
*/
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
log.warn("cros跨域完成");
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin")); //标识允许哪个域到请求,直接修改成请求头的域
httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");//标识允许的请求方法
// 响应首部 Access-Control-Allow-Headers 用于 preflight request (预检请求)中,列出了将会在正式请求的 Access-Control-Expose-Headers 字段中出现的首部信息。修改为请求首部
httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
//给option请求直接返回正常状态
if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
httpServletResponse.setStatus(HttpStatus.OK.value());
return false;
}
return true;
}
}
```
然后将这个filter挂载到我们的shrio里去,这样应该就解决了跨域的问题
```java
/**
* 将shiro过滤器交给spring管理
* @param securityManager
* @return
*/
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
//加入 安全管理器 管理所有Subject 相当于整体的管理人。
factoryBean.setSecurityManager(securityManager);
/**
* 设置无权访问的地址 当使用注解时这个地址就会失效,所以需要重写异常类
* 可查看 {@link MyExceptionResolver}
*/
factoryBean.setUnauthorizedUrl("/permission/not");
// 添加自己的过滤器并且取名为jwt
Map filterMap = new HashMap<>(4);
filterMap.put("jwt", new JwtFilter());
//添加跨域过滤器
filterMap.put("core", new CorsFilter());
factoryBean.setFilters(filterMap);
//基本系统级别权限配置
Map filterRuleMap = new HashMap<>();
// druid
filterRuleMap.put("/druid/**", "anon");
// 开放登陆接口
filterRuleMap.put("/user/login", "anon");
// 所有请求通过我们自己的JWT Filter 这里没有配置会导致配置
// org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported
//所有请求经过这两个过滤器
filterRuleMap.put("/**", "core, jwt");
factoryBean.setFilterChainDefinitionMap(filterRuleMap);
return factoryBean;
}
```
参考链接:
```html
https://blog.csdn.net/qq_40585384/article/details/105345435
```
```
https://www.cnblogs.com/sxdcgaq8080/p/6744371.html
```
```
https://www.cnblogs.com/dadiwm321/p/shiro_jwt.html
```