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(); } } }