Java安全框架——Apache Shiro(三十)

102 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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;
}
}