jiangping
2023-08-29 65d26bd2be023009c3617ba5ee0ddb85442e86b6
redis缓存session
已添加12个文件
已修改8个文件
1048 ■■■■■ 文件已修改
server/src/main/java/doumeemes/config/shiro/ShiroCache.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiro/ShiroCacheManager.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiro/ShiroConfig.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiro/ShiroCredentialsMatcher.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiro/ShiroRealm.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiro/ShiroSessionDAO.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiro/ShiroToken.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiro/ShiroTokenManager.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiroRedis/ShiroAuthFilter.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiroRedis/ShiroCache.java 159 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiroRedis/ShiroCacheManager.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiroRedis/ShiroConfig.java 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiroRedis/ShiroCredentialsMatcher.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiroRedis/ShiroRealm.java 166 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiroRedis/ShiroRedisSessionDAO.java 139 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionDAO.java 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionManager.java 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionSerializer.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiroRedis/ShiroToken.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiroRedis/ShiroTokenManager.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/src/main/java/doumeemes/config/shiro/ShiroCache.java
@@ -20,9 +20,9 @@
 * @author Eva.Caesar Liu
 * @date 2022/04/18 18:12
 */
@Scope(value = "prototype")
//@Scope(value = "prototype")
@Slf4j
@Component
//@Component
public class ShiroCache implements Cache<Object, Serializable> {
    private String keyPrefix = "";
server/src/main/java/doumeemes/config/shiro/ShiroCacheManager.java
@@ -17,7 +17,7 @@
 * @date 2022/04/18 18:12
 */
@Slf4j
@Component
//@Component
public class ShiroCacheManager implements CacheManager {
    private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap();
server/src/main/java/doumeemes/config/shiro/ShiroConfig.java
@@ -22,7 +22,7 @@
 * @author Eva.Caesar Liu
 * @date 2022/04/18 18:12
 */
@Configuration
//@Configuration
public class ShiroConfig {
    @Value("${cache.session.expire}")
server/src/main/java/doumeemes/config/shiro/ShiroCredentialsMatcher.java
@@ -15,7 +15,7 @@
 * @author Eva.Caesar Liu
 * @date 2022/04/18 18:12
 */
@Component
//@Component
public class ShiroCredentialsMatcher extends HashedCredentialsMatcher {
    @Lazy
server/src/main/java/doumeemes/config/shiro/ShiroRealm.java
@@ -44,7 +44,7 @@
 * @author Eva.Caesar Liu
 * @date 2022/04/18 18:12
 */
@Component
//@Component
public class ShiroRealm extends AuthorizingRealm {
    @Lazy
server/src/main/java/doumeemes/config/shiro/ShiroSessionDAO.java
@@ -17,9 +17,9 @@
 * @author Eva.Caesar Liu
 * @date 2022/04/18 18:12
 */
@Data
//@Data
@Slf4j
@Component
//@Component
public class ShiroSessionDAO implements SessionDAO {
    private static final String KEY_PREFIX = "shiro:session:";
server/src/main/java/doumeemes/config/shiro/ShiroToken.java
@@ -28,7 +28,7 @@
 * @author Eva.Caesar Liu
 * @date 2022/04/18 18:12
 */
@Component
//@Component
public class ShiroToken extends UsernamePasswordToken {
    /**
server/src/main/java/doumeemes/config/shiro/ShiroTokenManager.java
@@ -10,7 +10,7 @@
 * @author Eva.Caesar Liu
 * @date 2022/04/18 18:12
 */
@Component
//@Component
public class ShiroTokenManager {
    String build() {
server/src/main/java/doumeemes/config/shiroRedis/ShiroAuthFilter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
package doumeemes.config.shiroRedis;
import com.alibaba.fastjson.JSON;
import doumeemes.core.model.ApiResponse;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.http.HttpStatus;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
/**
 * Shiro认证过滤器,处理未认证情况的响应
 * @author Eva.Caesar Liu
 * @date 2023/04/17 12:11
 */
public class ShiroAuthFilter extends FormAuthenticationFilter {
    public ShiroAuthFilter() {
        super();
    }
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletResponse servletResponse = (HttpServletResponse) response;
        servletResponse.setHeader("content-type", "application/json;charset=UTF-8");
        servletResponse.getWriter().write(JSON.toJSONString(ApiResponse.failed(HttpStatus.UNAUTHORIZED.value(), "未登录或登录信息已过期")));
        return Boolean.FALSE;
    }
}
server/src/main/java/doumeemes/config/shiroRedis/ShiroCache.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,159 @@
package doumeemes.config.shiroRedis;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.context.annotation.Scope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
 * Shiro缓存
 * @author Eva.Caesar Liu
 * @date 2023/04/17 12:11
 */
@Scope(value = "prototype")
@Slf4j
@Component
public class ShiroCache implements Cache<Object, Serializable> {
    private String keyPrefix = "";
    @Resource(name="sessionRedisTemplate")
    private RedisTemplate<Object, Serializable> redisTemplate;
    public ShiroCache () {
        log.debug("ShiroCache: new, keyPrefix = [" + keyPrefix + "]");
    }
    public ShiroCache(String keyPrefix) {
        log.debug("ShiroCache: new, keyPrefix = [" + keyPrefix + "]");
        this.keyPrefix = keyPrefix;
    }
    @Override
    public Serializable get(Object key) throws CacheException {
        if (key == null) {
            return null;
        }
        return redisTemplate.opsForValue().get(getKey(key));
    }
    @Override
    public Serializable put(Object key, Serializable value) throws CacheException {
        if (key == null) {
            return null;
        }
        redisTemplate.opsForValue().set(getKey(key), value);
        return value;
    }
    public Serializable put(Object key, Serializable value, int timeout) throws CacheException {
        if (key == null) {
            return null;
        }
        redisTemplate.opsForValue().set(getKey(key), value, timeout, TimeUnit.SECONDS);
        return value;
    }
    @Override
    public void clear() throws CacheException {
        Set<Object> keys = this.keys();
        redisTemplate.delete(keys);
    }
    @Override
    public int size() {
        return this.keys().size();
    }
    @Override
    public Set<Object> keys() {
        Set<Object> keys = redisTemplate.keys(keyPrefix + "*");
        if (CollectionUtils.isEmpty(keys)) {
            return Collections.emptySet();
        }
        return keys;
    }
    @Override
    public Collection<Serializable> values() {
        Collection<Serializable> values = new ArrayList<>();
        Set<Object> keys = this.keys();
        if (CollectionUtils.isEmpty(keys)) {
            return values;
        }
        for (Object k : keys) {
            values.add(redisTemplate.opsForValue().get(k));
        }
        return values;
    }
    @Override
    public Serializable remove(Object key) throws CacheException {
        if (key == null) {
            return null;
        }
        Serializable value = this.get(getKey(key));
        redisTemplate.delete(getKey(key));
        return value;
    }
    private Object getKey (Object key) {
        if (key instanceof PrincipalCollection) {
            return this.keyPrefix + getRedisKeyFromPrincipalIdField((PrincipalCollection)key);
        }
        return (key instanceof String ? (this.keyPrefix + key) : key);
    }
    /**
     * èŽ·å–redis cache key
     */
    private String getRedisKeyFromPrincipalIdField(PrincipalCollection key) {
        Object principalObject = key.getPrimaryPrincipal();
        if (principalObject instanceof String) {
            return principalObject.toString();
        } else {
            Method pincipalIdGetter = this.getPrincipalIdGetter(principalObject);
            return this.getIdObj(principalObject, pincipalIdGetter);
        }
    }
    private Method getPrincipalIdGetter(Object principalObject) {
        Method pincipalIdGetter;
        String principalIdMethodName = this.getPrincipalIdMethodName();
        try {
            pincipalIdGetter = principalObject.getClass().getMethod(principalIdMethodName);
            return pincipalIdGetter;
        } catch (NoSuchMethodException e) {
            throw new SerializationException(e.getMessage(), e);
        }
    }
    private String getIdObj(Object principalObject, Method pincipalIdGetter) {
        try {
            Object idObj = pincipalIdGetter.invoke(principalObject);
            String redisKey = idObj.toString();
            return redisKey;
        } catch (Exception e) {
            throw new SerializationException(e.getMessage(), e);
        }
    }
    private String getPrincipalIdMethodName() {
        return "getId";
    }
}
server/src/main/java/doumeemes/config/shiroRedis/ShiroCacheManager.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
package doumeemes.config.shiroRedis;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
 * è‡ªå®šä¹‰Shiro CacheManager
 * @author Eva.Caesar Liu
 * @date 2023/04/17 12:11
 */
@Slf4j
@Component
public class ShiroCacheManager implements CacheManager {
    private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap();
    private static ApplicationContext applicationContext;
    @Override
    public <K, V> Cache<K, V> getCache(String name) throws CacheException {
        log.debug("get cache, name=" + name);
        Cache cache = this.caches.get(name);
        if (cache == null) {
            cache = applicationContext.getBean(ShiroCache.class, "shiro:cache:");
            this.caches.put(name, cache);
        }
        return cache;
    }
    @Autowired
    public void setApplicationContext (ApplicationContext applicationContext) {
        if (ShiroCacheManager.applicationContext == null) {
            ShiroCacheManager.applicationContext = applicationContext;
        }
    }
}
server/src/main/java/doumeemes/config/shiroRedis/ShiroConfig.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,129 @@
package doumeemes.config.shiroRedis;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import javax.servlet.Filter;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
/**
 * Shiro配置
 * @author Eva.Caesar Liu
 * @date 2023/04/17 12:11
 */
@Configuration
public class ShiroConfig {
    @Value("${cache.session.expire}")
    private int sessionExpireTime;
    @Autowired
    private ShiroCredentialsMatcher shiroCredentialsMatcher;
    @Autowired
    private ShiroSessionDAO shiroSessionDAO;
    @Autowired
    private ShiroCacheManager shiroCacheManager;
    @Autowired
    private ShiroRealm shiroRealm;
    @Bean("sessionRedisTemplate")
    public RedisTemplate<Object, Serializable> sessionRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Serializable> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // é»˜è®¤åºåˆ—化方式
        redisTemplate.setDefaultSerializer(new StringRedisSerializer());
        // å€¼åºåˆ—化方式
        ShiroSessionSerializer serializer = new ShiroSessionSerializer();
        redisTemplate.setValueSerializer(serializer);
        redisTemplate.setHashValueSerializer(serializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        autoProxyCreator.setProxyTargetClass(true);
        return autoProxyCreator;
    }
    @Bean
    public SessionManager sessionManager() {
        ShiroSessionManager sessionManager = new ShiroSessionManager();
        sessionManager.setSessionDAO(shiroSessionDAO);
        return sessionManager;
    }
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(shiroRealm);
        securityManager.setSessionManager(this.sessionManager());
        securityManager.setCacheManager(shiroCacheManager);
        return securityManager;
    }
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, String> map = new LinkedHashMap<>();
        // è·¯å¾„拦截配置
        map.put("/web/user/login", "anon");
        map.put("/public/uploadRichText", "anon");
        map.put("/system/login", "anon");
        map.put("/system/logout", "anon");
        map.put("/common/captcha", "anon");
        //放行 scratch æŽ¥å£
        map.put("/web/scratch/**", "anon");
        // - æ”¾è¡Œswagger
        map.put("/doc.html", "anon");
        map.put("/webjars/**", "anon");
        map.put("/swagger-resources/**", "anon");
        map.put("/v2/api-docs/**", "anon");
        // - å…¶ä»–接口统一拦截
        map.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        // æ·»åŠ è®¤è¯è¿‡æ»¤å™¨
        Map<String, Filter> filters = new LinkedHashMap<>();
        filters.put("authc", new ShiroAuthFilter());
        shiroFilterFactoryBean.setFilters(filters);
        return shiroFilterFactoryBean;
    }
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
    @Bean
    public ShiroSessionDAO getShiroSessionDAO () {
        shiroSessionDAO.setExpireTime(sessionExpireTime);
        return shiroSessionDAO;
    }
    @Bean
    public ShiroRealm getShiroRealm () {
        shiroRealm.setCredentialsMatcher(shiroCredentialsMatcher);
        return shiroRealm;
    }
}
server/src/main/java/doumeemes/config/shiroRedis/ShiroCredentialsMatcher.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
package doumeemes.config.shiroRedis;
import doumeemes.config.shiro.ShiroToken;
import doumeemes.core.utils.Utils;
import doumeemes.dao.system.model.SystemUser;
import doumeemes.service.system.SystemUserService;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
/**
 * Shiro密码比对处理
 * @author Eva.Caesar Liu
 * @date 2023/04/17 12:11
 */
@Component
public class ShiroCredentialsMatcher extends HashedCredentialsMatcher {
    @Lazy
    @Autowired
    private SystemUserService systemUserService;
    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        doumeemes.config.shiro.ShiroToken usernamePasswordToken = (ShiroToken) token;
        SystemUser queryUserDto = new SystemUser();
        queryUserDto.setUsername(usernamePasswordToken.getUsername());
        queryUserDto.setDeleted(Boolean.FALSE);
        SystemUser systemUser = systemUserService.findOne(queryUserDto);
        if (systemUser == null) {
            return Boolean.FALSE;
        }
        if(usernamePasswordToken.getDdLogin()){
            return Boolean.TRUE;
        }
        if(usernamePasswordToken.getWxLogin()){
            return Boolean.TRUE;
        }
        // åŠ å¯†å¯†ç 
        String pwd = Utils.Secure.encryptPassword(new String(usernamePasswordToken.getPassword()), systemUser.getSalt());
        // æ¯”较密码
        return this.equals(pwd, systemUser.getPassword());
    }
}
server/src/main/java/doumeemes/config/shiroRedis/ShiroRealm.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,166 @@
package doumeemes.config.shiroRedis;
import doumeemes.core.constants.ResponseStatus;
import doumeemes.core.exception.BusinessException;
import doumeemes.core.model.LoginUserInfo;
import doumeemes.core.utils.Constants;
import doumeemes.dao.ext.dto.QueryCompanyUserExtDTO;
import doumeemes.dao.ext.vo.CompanyExtListVO;
import doumeemes.dao.ext.vo.CompanyUserExtListVO;
import doumeemes.dao.ext.vo.DepartmentExtListVO;
import doumeemes.dao.system.model.SystemDataPermission;
import doumeemes.dao.system.model.SystemPermission;
import doumeemes.dao.system.model.SystemRole;
import doumeemes.dao.system.model.SystemUser;
import doumeemes.service.ext.CompanyExtService;
import doumeemes.service.ext.CompanyUserExtService;
import doumeemes.service.ext.DepartmentExtService;
import doumeemes.service.system.SystemDataPermissionService;
import doumeemes.service.system.SystemPermissionService;
import doumeemes.service.system.SystemRoleService;
import doumeemes.service.system.SystemUserService;
import org.apache.commons.lang3.StringUtils;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
/**
 * è‡ªå®šä¹‰Realm,处理认证和权限
 * @author Eva.Caesar Liu
 * @date 2022/03/15 09:54
 */
@Component
public class ShiroRealm extends AuthorizingRealm {
    @Lazy
    @Autowired
    private DepartmentExtService departmentExtService;
    @Lazy
    @Autowired
    private SystemDataPermissionService systemDataPermissionService;
    @Lazy
    @Autowired
    private CompanyExtService companyExtService;
    @Lazy
    @Autowired
    private SystemUserService systemUserService;
    @Lazy
    @Autowired
    private CompanyUserExtService companyUserExtService;
    @Lazy
    @Autowired
    private SystemRoleService systemRoleService;
    @Lazy
    @Autowired
    private SystemPermissionService systemPermissionService;
    /**
     * æƒé™å¤„理
     * @author Eva.Caesar Liu
     * @date 2022/03/15 09:54
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        LoginUserInfo loginUserInfo = (LoginUserInfo)principalCollection.getPrimaryPrincipal();
        // è®¾ç½®ç”¨æˆ·è§’色和权限
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.addRoles(loginUserInfo.getRoles());
        authorizationInfo.addStringPermissions(loginUserInfo.getPermissions());
        return authorizationInfo;
    }
    /**
     * è®¤è¯å¤„理
     * @author Eva.Caesar Liu
     * @date 2022/03/15 09:54
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // èŽ·å–ç”¨æˆ·å
        ShiroToken authenticationToken =(ShiroToken) token;
        String username = authenticationToken.getPrincipal().toString();
        boolean isDdLogin = authenticationToken.getDdLogin();
        // æ ¹æ®ç”¨æˆ·åæŸ¥è¯¢ç”¨æˆ·å¯¹è±¡
        SystemUser queryDto = new SystemUser();
        queryDto.setUsername(username);
        queryDto.setDeleted(Boolean.FALSE);
        SystemUser user = systemUserService.findOne(queryDto);
        if (user == null) {
            return null;
        }
        SystemRole role = new SystemRole();
        SystemPermission per = new SystemPermission();
        DepartmentExtListVO rootDepart = null,comDepart=null, depart = null;
        List<Integer> dpList = null;
        CompanyExtListVO com = null;
        CompanyUserExtListVO cu =null;
        if(Constants.equalsInteger(user.getType(),Constants.PlatType.admin)){
            //如果是平台用户
            role.setType(Constants.ROLETYPE.plat);
            per.setType(Constants.PlatType.admin);
        }else{
            if(authenticationToken.getCompanyId() == null){
                throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"对不起,该账户删除!");
            }
            com = companyExtService.getModelById(authenticationToken.getCompanyId());
            if(com == null || Constants.equalsInteger( com.getDeleted(),Constants.ONE)){
                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"对不起,该账户删除!请联系管理员");
            }
            if(Constants.equalsInteger( com.getStatus(),Constants.ZERO) ){
                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"对不起,该企业已禁用!");
            }
            if(com.getOepnValidDate() != null && com.getOepnValidDate().before(new Date())){
                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"对不起,该企业已过使用有效期!");
            }
            //如果是企业用户
            QueryCompanyUserExtDTO c =new QueryCompanyUserExtDTO();
            c.setUserId(user.getId());
            c.setDeleted(Constants.ZERO);
            c.setCompanyId(authenticationToken.getCompanyId());
            cu = companyUserExtService.selectOne(c);
            if(cu == null){
                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"对不起,该企业用户不存在!");
            }
            if(Constants.equalsInteger(cu.getStatus(),Constants.ONE)){
                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"对不起,该企业用户已禁用!");
            }
            rootDepart = departmentExtService.getModelById(c.getCompanyId(),cu.getRootDepartId());
            comDepart = departmentExtService.getModelById(c.getCompanyId(),cu.getComDepartId());
            depart = departmentExtService.getModelById(c.getCompanyId(),cu.getDepartmentId());
            if(rootDepart == null || comDepart == null || depart==null){
                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"对不起,该企业用户账户异常!");
            }
            role.setCompanyId(authenticationToken.getCompanyId());
            role.setType(Constants.ROLETYPE.com);
            per.setType(Constants.PlatType.company);
            per.setRoleType(Constants.ROLETYPE.com);
            per.setCompanyId(authenticationToken.getCompanyId());
            SystemRole rt = new SystemRole();
            rt.setType(Constants.ROLETYPE.com);
            rt.setCompanyId(c.getCompanyId());
            //数据部门权限集合
            dpList =systemDataPermissionService.selectHighRole(new SystemDataPermission(),rt,user,depart);
        }
        // èŽ·å–ç™»å½•ç”¨æˆ·ä¿¡æ¯
        List<SystemRole> roles = systemRoleService.findByUserModel(user.getId(),role);
        List<SystemPermission> permissions = systemPermissionService.findByUserModel(user.getId(),per);
        LoginUserInfo userInfo = LoginUserInfo.from(user, roles, permissions,com,rootDepart,comDepart,depart,dpList,cu);
        // éªŒè¯ç”¨æˆ·
        return new SimpleAuthenticationInfo(userInfo, user.getPassword(), this.getName());
    }
}
server/src/main/java/doumeemes/config/shiroRedis/ShiroRedisSessionDAO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,139 @@
package doumeemes.config.shiroRedis;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.SerializationUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.io.Serializable;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
//@Component
@Slf4j
@SuppressWarnings({ "rawtypes", "unchecked" })
public class ShiroRedisSessionDAO  implements SessionDAO {
// Session超时时间,单位为毫秒
private static final String KEY_PREFIX = "shiro:session:";
    private long expireTime = 120000;
    @Autowired
    private ShiroTokenManager shiroTokenManager;
    @Autowired
    private RedisTemplate redisTemplate;// Redis操作类,对这个使用不熟悉的,可以参考前面的博客
    public ShiroRedisSessionDAO() {
        super();
    }
    public ShiroRedisSessionDAO(long expireTime, StringRedisTemplate redisTemplate) {
        super();
        this.expireTime = expireTime;
        this.redisTemplate = redisTemplate;
    }
    @Override // æ›´æ–°session
    public void update(Session session) throws UnknownSessionException {
        System.out.println("===============update================");
        if (session == null || session.getId() == null) {
            return;
        }
        session.setTimeout(expireTime);
        byte[] bytes = SerializationUtils.serialize((Serializable) session);
        redisTemplate.opsForValue().set(KEY_PREFIX+session.getId(), bytes, expireTime, TimeUnit.MILLISECONDS);
    }
    @Override // åˆ é™¤session
    public void delete(Session session) {
        System.out.println("===============delete================");
        if (null == session) {
            return;
        }
        redisTemplate.opsForValue().getOperations().delete(KEY_PREFIX+session.getId());
    }
    @Override// èŽ·å–æ´»è·ƒçš„session,可以用来统计在线人数,如果要实现这个功能,可以在将session加入redis时指定一个session前缀,统计的时候则使用keys("session-prefix*")的方式来模糊查找redis中所有的session集合
    public Collection getActiveSessions() {
        System.out.println("==============getActiveSessions=================");
        return redisTemplate.keys("*");
    }
    @Override
    public Serializable create(Session session) {
        System.out.println("===============doCreate================");
        if (session == null) {
            log.error("session is null");
            throw new UnknownSessionException("session is null");
        }
        Serializable sessionId = shiroTokenManager.build();
        ((SimpleSession)session).setId(sessionId);
        byte[] bytes = SerializationUtils.serialize((Serializable) session);
        redisTemplate.opsForValue().set(session.getId(), bytes, expireTime, TimeUnit.MILLISECONDS);
        return sessionId;
    }
    public Session readSession(Serializable sessionId) throws UnknownSessionException{
        if (sessionId == null) {
            log.warn("session id is null");
            return null;
        }
        if (sessionId instanceof String) {
            // å¯¹SessionId进行验证(可用于防止Session捕获、暴力捕捉等一系列安全问题,最终安全性取决于check如何实现)
            shiroTokenManager.check((String) sessionId);
        }
        log.debug("read session from cache");
        SimpleSession simpleSession = (SimpleSession) SerializationUtils.deserialize((byte[])redisTemplate.opsForValue().get(KEY_PREFIX+sessionId));
       return simpleSession;
    }
    public long getExpireTime() {
        return expireTime;
    }
    public void setExpireTime(long expireTime) {
        this.expireTime = expireTime;
    }
    public RedisTemplate getRedisTemplate() {
        return redisTemplate;
    }
    public void setRedisTemplate(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
}
server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionDAO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,113 @@
package doumeemes.config.shiroRedis;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
 * è‡ªå®šä¹‰Shiro SessionDAO,将会话信息存入缓存中
 * @author Eva.Caesar Liu
 * @date 2023/04/17 12:11
 */
@Data
@Slf4j
@Component
public class ShiroSessionDAO implements SessionDAO {
    private static final String KEY_PREFIX = "shiro:session:";
    @Autowired
    private ShiroCache shiroCache;
    private int expireTime = 60 * 60 * 24;
    @Autowired
    private ShiroTokenManager shiroTokenManager;
    @Override
    public Serializable create(Session session) {
        if (session == null) {
            log.error("session is null");
            throw new UnknownSessionException("session is null");
        }
        Serializable sessionId = shiroTokenManager.build();
        ((SimpleSession)session).setId(sessionId);
        this.saveSession(session);
        return sessionId;
    }
    @Override
    public Session readSession(Serializable sessionId) throws UnknownSessionException{
        if (sessionId == null) {
            log.warn("session id is null");
            return null;
        }
        if (sessionId instanceof String) {
            // å¯¹SessionId进行验证(可用于防止Session捕获、暴力捕捉等一系列安全问题,最终安全性取决于check如何实现)
            shiroTokenManager.check((String) sessionId);
        }
        log.debug("read session from cache");
        Session session = getSessionFromCache(sessionId);
        if (session == null) {
            throw new UnknownSessionException("There is no session with id [" + sessionId + "]");
        }
        return session;
    }
    @Override
    public void update(Session session) throws UnknownSessionException {
        this.saveSession(session);
    }
    @Override
    public void delete(Session session) {
        if (session != null && session.getId() != null) {
            shiroCache.remove(KEY_PREFIX + session.getId());
        }
    }
    @Override
    public Collection<Session> getActiveSessions() {
        Set<Session> sessions = new HashSet<>();
        Set<Object> keys = shiroCache.keys();
        if (keys != null && keys.size() > 0) {
            Iterator iter = keys.iterator();
            while(iter.hasNext()) {
                sessions.add((Session) shiroCache.get(iter.next()));
            }
        }
        return sessions;
    }
    private void saveSession(Session session) throws UnknownSessionException {
        if (session == null || session.getId() == null) {
            log.error("session or session id is null");
            throw new UnknownSessionException("session or session id is null");
        }
        shiroCache.put(KEY_PREFIX + session.getId(), (SimpleSession)session, expireTime);
    }
    private Session getSessionFromCache (Serializable sessionId) {
        Serializable object = shiroCache.get(KEY_PREFIX + sessionId);
        Session session = null;
        if (object != null) {
            session = (Session)shiroCache.get(KEY_PREFIX + sessionId);
        }
        return session;
    }
    public void setExpireTime (int expireTime) {
        this.expireTime = expireTime;
    }
}
server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionManager.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,86 @@
package doumeemes.config.shiroRedis;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.session.mgt.SessionContext;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.WebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
/**
 * è‡ªå®šä¹‰ä¼šè¯ç®¡ç†å™¨
 * @author Eva.Caesar Liu
 * @date 2023/04/17 12:11
 */
@Slf4j
public class ShiroSessionManager extends DefaultSessionManager implements WebSessionManager {
    private static final String AUTH_TOKEN = "eva-auth-token";
    @Override
    protected void onStart(Session session, SessionContext context) {
        super.onStart(session, context);
        if (!WebUtils.isHttp(context)) {
            log.debug("SessionContext argument is not Http compatible or does not have an Http request/response pair. No session ID cookie will be set.");
            return;
        }
        HttpServletRequest request = WebUtils.getHttpRequest(context);
        HttpServletResponse response = WebUtils.getHttpResponse(context);
        Serializable sessionId = session.getId();
        this.storeSessionId(sessionId, request, response);
        request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE);
        request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_IS_NEW, Boolean.TRUE);
    }
    @Override
    public Serializable getSessionId(SessionKey key) {
        Serializable sessionId = super.getSessionId(key);
        if (sessionId == null && WebUtils.isWeb(key)) {
            ServletRequest servletRequest = WebUtils.getRequest(key);
            if (!(servletRequest instanceof HttpServletRequest)) {
                log.trace("Can not get sessionId from header, the request is not HttpServletRequest");
                return null;
            }
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            // ä»Žcookie中获取认证
            javax.servlet.http.Cookie[] cookies = request.getCookies();
            if (cookies != null) {
                for (javax.servlet.http.Cookie cookie : cookies) {
                    if (AUTH_TOKEN.equals(cookie.getName())) {
                        return cookie.getValue();
                    }
                }
            }
            // ä»Žheader中获取认证
            return request.getHeader(AUTH_TOKEN);
        }
        return sessionId;
    }
    @Override
    public boolean isServletContainerSessions() {
        return false;
    }
    private void storeSessionId(Serializable currentId, HttpServletRequest request, HttpServletResponse response) {
        if (currentId == null) {
            String msg = "sessionId cannot be null when persisting for subsequent requests.";
            throw new IllegalArgumentException(msg);
        }
        Cookie cookie = new SimpleCookie(AUTH_TOKEN);
        cookie.setHttpOnly(false);
        String idString = currentId.toString();
        cookie.setValue(idString);
        cookie.saveTo(request, response);
        log.trace("Set session ID cookie for session with id {}", idString);
    }
}
server/src/main/java/doumeemes/config/shiroRedis/ShiroSessionSerializer.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
package doumeemes.config.shiroRedis;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.shiro.codec.Base64;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
/**
 * Session序列化
 * @author Eva.Caesar Liu
 * @date 2023/04/17 12:11
 */
public class ShiroSessionSerializer implements RedisSerializer<Serializable> {
    @Override
    public byte[] serialize(Serializable obj) throws SerializationException {
        if (obj == null) {
            return new byte[0];
        }
        String sessionBase64 = Base64.encodeToString(SerializationUtils.serialize(obj));
        return sessionBase64.getBytes(StandardCharsets.UTF_8);
    }
    @Override
    public Serializable deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        String sessionString = new String(bytes, StandardCharsets.UTF_8);
        byte[] sessionBytes = Base64.decode(sessionString);
        return SerializationUtils.deserialize(sessionBytes);
    }
}
server/src/main/java/doumeemes/config/shiroRedis/ShiroToken.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,54 @@
package doumeemes.config.shiroRedis;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.springframework.stereotype.Component;
/**
 * è‡ªå®šä¹‰Token ï¼Œå¤„理认证和权限
 * @author Eva.Caesar Liu
 * @date 2022/04/18 18:12
 */
@Component
public class ShiroToken extends UsernamePasswordToken {
    /**
     * å…¬å¸ID
     */
    Integer companyId;
    Boolean isDdLogin;
    Boolean isWxLogin;
    public ShiroToken() {
    }
    public ShiroToken(Integer companyId, String username, String password, boolean isDdLogin, boolean isWxLogin) {
        super(username,  password, false, (String)null);
        this.companyId = companyId;
        this.isDdLogin = isDdLogin;
        this.isWxLogin = isWxLogin;
    }
    public Boolean getDdLogin() {
        return isDdLogin;
    }
    public void setDdLogin(Boolean ddLogin) {
        isDdLogin = ddLogin;
    }
    public Boolean getWxLogin() {
        return isWxLogin;
    }
    public void setWxLogin(Boolean wxLogin) {
        isWxLogin = wxLogin;
    }
    public Integer getCompanyId() {
        return companyId;
    }
    public void setCompanyId(Integer companyId) {
        this.companyId = companyId;
    }
}
server/src/main/java/doumeemes/config/shiroRedis/ShiroTokenManager.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
package doumeemes.config.shiroRedis;
import doumeemes.core.exception.UnSafeSessionException;
import org.springframework.stereotype.Component;
import java.util.UUID;
/**
 * é»˜è®¤Token管理器
 * @author Eva.Caesar Liu
 * @date 2023/04/17 12:11
 */
@Component
public class ShiroTokenManager {
    String build() {
        return UUID.randomUUID().toString();
    }
    void check(String token) throws UnSafeSessionException {
        if (token == null || token.length() != 36) {
            throw new UnSafeSessionException();
        }
    }
}