spring boot + shiro + jwt + redis
一、场景描述
1、前言
基于上一篇spring boot 整合shiro,当时想把shiro引入到我们的spring boot中,引入完了之后,我发现一个问题,那就是shiro是基于session的。那么我是不是可以引入到接口来做呢?比如我们的会员系统,会员分为好几个级别【白银、黄金、铂金、钻石、星耀、王者、荣耀王者】,目前只有王者和荣耀王者才可以打巅峰赛。
2、模拟逻辑(纯属杜撰)
我们先模拟一种场景
角色有:silver、gold、platinum、diamonds、starshine、king、glory
会员有:user1、user2、user3…userX
权限有:common_activity(普通活动)、star_activity(星耀活动)、king_activity(王者活动)、call_up_mode(征召模式)、common_mode(普通竞技模式)…
我们可以说,首先配置角色和权限关系
1、silver、gold、platinum、diamonds、starshine、king、glory 都有 common_activity、common_mode
2、diamonds、starshine、king、glory 都有call_up_mode
2、starshine、king、glory 都有 star_activity
3、king、glory 都有 king_activity
写到这里,大家觉得也没毛病啊,就用shiro做权限管理,没问题的,但是因为我们兼容安卓和IOS,所以是不是涉及到前后端分离呢?这样session无效了,怎么办。
3、JWT如何配合shiro来完成权限
这个相关的文章一大堆:
1、spring-boot-shiro-jwt-redis实现登陆授权功能
2、spring-boot-shiro-jwt-redis
这类文章太多了,我们就不在赘述了,不过这里有一个东西可以注意一下。
/*
* 关闭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);
这玩意如果不知道在哪?可以看看上面2篇参考文章。这里是说要把session关闭的一个逻辑,同时备注上也说了,参考:关闭shiro自带的session,详情见文档
二、度娘告诉我们的做法
1、每次都需要登录
我们可以结合他的shiroConfig对于JwtFilter的注入知道,每个请求,都必须先登录,然后在做权限判断。
JwtFilter
/**
* 执行登录认证
*
* @param request
* @param response
* @param mappedValue
* @return
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
try {
executeLogin(request, response);
return true;
} catch (Exception e) {
throw new AuthenticationException("Token失效请重新登录");
}
}
/**
*
*/
@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String token = httpServletRequest.getHeader(CommonConstant.ACCESS_TOKEN);
JwtToken jwtToken = new JwtToken(token);
// 提交给realm进行登入,如果错误他会抛出异常并被捕获
getSubject(request, response).login(jwtToken);
// 如果没有抛出异常则代表登入成功,返回true
return true;
}
shiroRealm类
/**
* 功能: 用来进行身份认证,也就是说验证用户输入的账号和密码是否正确,获取身份验证信息,错误抛出异常
*
* @param auth 用户身份信息 token
* @return 返回封装了用户信息的 AuthenticationInfo 实例
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
String token = (String) auth.getCredentials();
if (token == null) {
log.info("————————身份认证失败——————————IP地址: " + CommonUtils.getIpAddrByRequest(SpringContextUtils.getHttpServletRequest()));
throw new AuthenticationException("token为空!");
}
// 校验token有效性
SysUser loginUser = this.checkUserTokenIsEffect(token);
return new <