持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第22天,点击查看活动详情
第十一章 分布式统一权限系统
1、系统需求
【1】前后端分离
在第十章中我们已经实现,使用jwt的令牌实现,重写DefaultWebSessionManager,从ServletRequest获得jwtToken作为会话sessionId
package com.itheima.shiro.core.impl;
import com.itheima.shiro.utils.EmptyUtil;
import io.jsonwebtoken.Claims;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;
/**
* @Description 重写Jwt会话管理
*/
public class ShiroSessionManager extends DefaultWebSessionManager {
private static final String AUTHORIZATION = "jwtToken";
private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
public ShiroSessionManager(){
super();
}
@Autowired
JwtTokenManager jwtTokenManager;
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response){
String jwtToken = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
if(EmptyUtil.isNullOrEmpty(jwtToken)){
//如果没有携带id参数则按照父类的方式在cookie进行获取
return super.getSessionId(request, response);
}else{
//如果请求头中有 authToken 则其值为jwtToken,然后解析出会话session
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,REFERENCED_SESSION_ID_SOURCE);
Claims decode = jwtTokenManager.decodeToken(jwtToken);
String id = (String) decode.get("jti");
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID,id);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID,Boolean.TRUE);
return id;
}
}
}
【2】集中式会话
在第七章中RedisSessionDao继承AbstractSessionDAO,重写了会话的创建、读取、修改等操作,全部缓存于redis中
package com.itheima.shiro.core.impl;
import com.itheima.shiro.constant.CacheConstant;
import com.itheima.shiro.utils.ShiroRedissionSerialize;
import lombok.extern.log4j.Log4j2;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
/**
* @Description 实现shiro session的memcached集中式管理~
*/
@Log4j2
public class RedisSessionDao extends AbstractSessionDAO {
@Resource(name = "redissonClientForShiro")
RedissonClient redissonClient;
private Long globalSessionTimeout;
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = generateSessionId(session);
assignSessionId(session, sessionId);
// log.info("=============创建sessionId:{}",sessionId);
RBucket sessionIdRBucket = redissonClient.getBucket(CacheConstant.GROUP_CAS+sessionId.toString());
sessionIdRBucket.trySet(ShiroRedissionSerialize.serialize(session), globalSessionTimeout, TimeUnit.SECONDS);
return sessionId;
}
@Override
protected Session doReadSession(Serializable sessionId) {
RBucket sessionIdRBucket = redissonClient.getBucket(CacheConstant.GROUP_CAS+sessionId.toString());
Session session = (Session) ShiroRedissionSerialize.deserialize(sessionIdRBucket.get());
// log.info("=============读取sessionId:{}",session.getId().toString());
return session;
}
@Override
public void delete(Session session) {
// log.info("=============删除sessionId:{}",session.getId().toString());
RBucket sessionIdRBucket = redissonClient.getBucket(CacheConstant.GROUP_CAS+session.getId().toString());
sessionIdRBucket.delete();
}
@Override
public Collection getActiveSessions() {
return Collections.emptySet();
}
@Override
public void update(Session session) {
RBucket sessionIdRBucket = redissonClient.getBucket(CacheConstant.GROUP_CAS+session.getId().toString());
sessionIdRBucket.set(ShiroRedissionSerialize.serialize(session), globalSessionTimeout, TimeUnit.SECONDS);
// log.info("=============修改sessionId:{}",session.getId().toString());
}
public void setGlobalSessionTimeout(Long globalSessionTimeout) {
this.globalSessionTimeout = globalSessionTimeout;
}
}