pom.xml
@@ -34,10 +34,12 @@ <commons.fileupload.version>1.4</commons.fileupload.version> <velocity.version>1.7</velocity.version> <fastjson.version>1.2.78</fastjson.version> <jjwt.version>0.9.1</jjwt.version> <minio.version>8.2.2</minio.version> <poi.version>4.1.2</poi.version> <common-pool.version>2.10.0</common-pool.version> <commons-collections.version>3.2.2</commons-collections.version> <transmittable-thread-local.version>2.12.2</transmittable-thread-local.version> </properties> <!-- 依赖声明 --> @@ -173,6 +175,20 @@ <version>${fastjson.version}</version> </dependency> <!-- JWT --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>${jjwt.version}</version> </dependency> <!-- 线程传递值 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>transmittable-thread-local</artifactId> <version>${transmittable-thread-local.version}</version> </dependency> <!-- 公共资源池 --> <dependency> <groupId>org.apache.commons</groupId> ruoyi-auth/src/main/java/com/ruoyi/auth/controller/TokenController.java
@@ -10,8 +10,11 @@ import com.ruoyi.auth.form.RegisterBody; import com.ruoyi.auth.service.SysLoginService; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.utils.JwtUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.security.auth.AuthUtil; import com.ruoyi.common.security.service.TokenService; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.model.LoginUser; /** @@ -40,12 +43,12 @@ @DeleteMapping("logout") public R<?> logout(HttpServletRequest request) { LoginUser loginUser = tokenService.getLoginUser(request); if (StringUtils.isNotNull(loginUser)) String token = SecurityUtils.getToken(request); if (StringUtils.isNotEmpty(token)) { String username = loginUser.getUsername(); String username = JwtUtils.getUserName(token); // 删除用户缓存记录 tokenService.delLoginUser(loginUser.getToken()); AuthUtil.logoutByToken(token); // 记录用户退出日志 sysLoginService.logout(username); } ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysLoginService.java
@@ -8,10 +8,10 @@ import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.enums.UserStatus; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.ServletUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.ip.IpUtils; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.RemoteLogService; import com.ruoyi.system.api.RemoteUserService; import com.ruoyi.system.api.domain.SysLogininfor; ruoyi-common/ruoyi-common-core/pom.xml
@@ -41,6 +41,12 @@ <artifactId>spring-web</artifactId> </dependency> <!-- Transmittable ThreadLocal --> <dependency> <groupId>com.alibaba</groupId> <artifactId>transmittable-thread-local</artifactId> </dependency> <!-- Apache Commons Pool2 --> <dependency> <groupId>org.apache.commons</groupId> @@ -71,6 +77,18 @@ <artifactId>fastjson</artifactId> </dependency> <!-- Jwt --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> </dependency> <!-- Jaxb --> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> </dependency> <!-- Apache Lang3 --> <dependency> <groupId>org.apache.commons</groupId> ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java
@@ -8,6 +8,16 @@ public class CacheConstants { /** * 缓存有效期,默认720(分钟) */ public final static long EXPIRATION = 720; /** * 缓存刷新时间,默认120(分钟) */ public final static long REFRESH_TIME = 120; /** * 权限缓存前缀 */ public final static String LOGIN_TOKEN_KEY = "login_tokens:"; ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/Constants.java
@@ -97,10 +97,6 @@ */ public static final long CAPTCHA_EXPIRATION = 2; /** * 令牌有效期(分钟) */ public final static long TOKEN_EXPIRE = 720; /** * 参数管理 cache key ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/SecurityConstants.java
@@ -8,16 +8,6 @@ public class SecurityConstants { /** * 令牌自定义标识 */ public static final String TOKEN_AUTHENTICATION = "Authorization"; /** * 令牌前缀 */ public static final String TOKEN_PREFIX = "Bearer "; /** * 用户ID字段 */ public static final String DETAILS_USER_ID = "user_id"; @@ -41,4 +31,14 @@ * 内部请求 */ public static final String INNER = "inner"; /** * 用户标识 */ public static final String USER_KEY = "user_key"; /** * 登录用户 */ public static final String LOGIN_USER = "login_user"; } ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/TokenConstants.java
New file @@ -0,0 +1,25 @@ package com.ruoyi.common.core.constant; /** * Token的Key常量 * * @author ruoyi */ public class TokenConstants { /** * 令牌自定义标识 */ public static final String AUTHENTICATION = "Authorization"; /** * 令牌前缀 */ public static final String PREFIX = "Bearer "; /** * 令牌秘钥 */ public final static String SECRET = "abcdefghijklmnopqrstuvwxyz"; } ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/context/SecurityContextHolder.java
New file @@ -0,0 +1,88 @@ package com.ruoyi.common.core.context; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import com.alibaba.ttl.TransmittableThreadLocal; import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.text.Convert; import com.ruoyi.common.core.utils.StringUtils; /** * 获取当前线程变量中的 用户id、用户名称、Token等信息 * 注意: 必须在网关通过请求头的方法传入,同时在HeaderInterceptor拦截器设置值。 否则这里无法获取 * * @author ruoyi */ public class SecurityContextHolder { private static final TransmittableThreadLocal<Map<String, Object>> THREAD_LOCAL = new TransmittableThreadLocal<>(); public static void set(String key, Object value) { Map<String, Object> map = getLocalMap(); map.put(key, value == null ? StringUtils.EMPTY : value); } public static String get(String key) { Map<String, Object> map = getLocalMap(); return Convert.toStr(map.getOrDefault(key, StringUtils.EMPTY)); } public static <T> T get(String key, Class<T> clazz) { Map<String, Object> map = getLocalMap(); return StringUtils.cast(map.getOrDefault(key, null)); } public static Map<String, Object> getLocalMap() { Map<String, Object> map = THREAD_LOCAL.get(); if (map == null) { map = new ConcurrentHashMap<String, Object>(); THREAD_LOCAL.set(map); } return map; } public static void setLocalMap(Map<String, Object> threadLocalMap) { THREAD_LOCAL.set(threadLocalMap); } public static Long getUserId() { return Convert.toLong(get(SecurityConstants.DETAILS_USER_ID), 0L); } public static void setUserId(String account) { set(SecurityConstants.DETAILS_USER_ID, account); } public static String getUserName() { return get(SecurityConstants.DETAILS_USERNAME); } public static void setUserName(String username) { set(SecurityConstants.DETAILS_USERNAME, username); } public static String getUserKey() { return get(SecurityConstants.USER_KEY); } public static void setUserKey(String userKey) { set(SecurityConstants.USER_KEY, userKey); } public static void remove() { THREAD_LOCAL.remove(); } } ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/JwtUtils.java
New file @@ -0,0 +1,123 @@ package com.ruoyi.common.core.utils; import java.util.Map; import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.constant.TokenConstants; import com.ruoyi.common.core.text.Convert; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; /** * Jwt工具类 * * @author ruoyi */ public class JwtUtils { public static String secret = TokenConstants.SECRET; /** * 从数据声明生成令牌 * * @param claims 数据声明 * @return 令牌 */ public static String createToken(Map<String, Object> claims) { String token = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, secret).compact(); return token; } /** * 从令牌中获取数据声明 * * @param token 令牌 * @return 数据声明 */ public static Claims parseToken(String token) { return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); } /** * 根据令牌获取用户标识 * * @param token 令牌 * @return 用户ID */ public static String getUserKey(String token) { Claims claims = parseToken(token); return getValue(claims, SecurityConstants.USER_KEY); } /** * 根据令牌获取用户标识 * * @param claims 身份信息 * @return 用户ID */ public static String getUserKey(Claims claims) { return getValue(claims, SecurityConstants.USER_KEY); } /** * 根据令牌获取用户ID * * @param token 令牌 * @return 用户ID */ public static String getUserId(String token) { Claims claims = parseToken(token); return getValue(claims, SecurityConstants.DETAILS_USER_ID); } /** * 根据身份信息获取用户ID * * @param claims 身份信息 * @return 用户ID */ public static String getUserId(Claims claims) { return getValue(claims, SecurityConstants.DETAILS_USER_ID); } /** * 根据令牌获取用户名 * * @param token 令牌 * @return 用户名 */ public static String getUserName(String token) { Claims claims = parseToken(token); return getValue(claims, SecurityConstants.DETAILS_USERNAME); } /** * 根据身份信息获取用户名 * * @param claims 身份信息 * @return 用户名 */ public static String getUserName(Claims claims) { return getValue(claims, SecurityConstants.DETAILS_USERNAME); } /** * 根据身份信息获取键值 * * @param claims 身份信息 * @param key 键 * @return 值 */ public static String getValue(Claims claims, String key) { return Convert.toStr(claims.get(key), ""); } } ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java
@@ -130,6 +130,16 @@ } } public static String getHeader(HttpServletRequest request, String name) { String value = request.getHeader(name); if (StringUtils.isEmpty(value)) { return StringUtils.EMPTY; } return urlDecode(value); } public static Map<String, String> getHeaders(HttpServletRequest request) { Map<String, String> map = new LinkedHashMap<>(); @@ -216,7 +226,7 @@ } catch (UnsupportedEncodingException e) { return ""; return StringUtils.EMPTY; } } @@ -234,7 +244,7 @@ } catch (UnsupportedEncodingException e) { return ""; return StringUtils.EMPTY; } } ruoyi-common/ruoyi-common-datascope/src/main/java/com/ruoyi/common/datascope/aspect/DataScopeAspect.java
@@ -3,12 +3,11 @@ import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.web.domain.BaseEntity; import com.ruoyi.common.datascope.annotation.DataScope; import com.ruoyi.common.security.service.TokenService; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.domain.SysRole; import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.api.model.LoginUser; @@ -52,9 +51,6 @@ */ public static final String DATA_SCOPE = "dataScope"; @Autowired private TokenService tokenService; @Before("@annotation(controllerDataScope)") public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable { @@ -65,7 +61,7 @@ protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope) { // 获取当前的用户 LoginUser loginUser = tokenService.getLoginUser(); LoginUser loginUser = SecurityUtils.getLoginUser(); if (StringUtils.isNotNull(loginUser)) { SysUser currentUser = loginUser.getSysUser(); ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/aspect/LogAspect.java
@@ -16,13 +16,13 @@ import org.springframework.validation.BindingResult; import org.springframework.web.multipart.MultipartFile; import com.alibaba.fastjson.JSON; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.ServletUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.ip.IpUtils; import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.enums.BusinessStatus; import com.ruoyi.common.log.service.AsyncLogService; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.domain.SysOperLog; /** ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/service/RedisService.java
@@ -75,6 +75,17 @@ } /** * 获取有效时间 * * @param key Redis键 * @return 有效时间 */ public long getExpire(final String key) { return redisTemplate.getExpire(key); } /** * 判断 key是否存在 * * @param key 键 ruoyi-common/ruoyi-common-security/pom.xml
@@ -15,19 +15,25 @@ </description> <dependencies> <!-- Spring Web --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> <!-- RuoYi Api System --> <dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-api-system</artifactId> </dependency> <!-- RuoYi Common Redis--> <dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-common-redis</artifactId> </dependency> </dependencies> </project> ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/auth/AuthLogic.java
@@ -7,7 +7,6 @@ import com.ruoyi.common.core.exception.auth.NotLoginException; import com.ruoyi.common.core.exception.auth.NotPermissionException; import com.ruoyi.common.core.exception.auth.NotRoleException; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.security.annotation.Logical; @@ -15,6 +14,7 @@ import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.annotation.RequiresRoles; import com.ruoyi.common.security.service.TokenService; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.model.LoginUser; /** @@ -31,6 +31,27 @@ private static final String SUPER_ADMIN = "admin"; public TokenService tokenService = SpringUtils.getBean(TokenService.class); /** * 会话注销 */ public void logout() { String token = SecurityUtils.getToken(); if (token == null) { return; } logoutByToken(token); } /** * 会话注销,根据指定Token */ public void logoutByToken(String token) { tokenService.delLoginUser(token); } /** * 检验用户是否已经登录,如未登录,则抛出异常 @@ -52,7 +73,7 @@ { throw new NotLoginException("未提供token"); } LoginUser loginUser = tokenService.getLoginUser(token); LoginUser loginUser = SecurityUtils.getLoginUser(); if (loginUser == null) { throw new NotLoginException("无效的token"); @@ -61,6 +82,27 @@ } /** * 获取当前用户缓存信息, 如果未登录,则抛出异常 * * @param token 前端传递的认证信息 * @return 用户缓存信息 */ public LoginUser getLoginUser(String token) { return tokenService.getLoginUser(token); } /** * 验证当前用户有效期, 如果相差不足360分钟,自动刷新缓存 * * @param loginUser 当前用户信息 */ public void verifyLoginUserExpire(LoginUser loginUser) { tokenService.verifyToken(loginUser); } /** * 验证用户是否具备某权限 * * @param permission 权限字符串 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/auth/AuthUtil.java
@@ -2,6 +2,7 @@ import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.annotation.RequiresRoles; import com.ruoyi.system.api.model.LoginUser; /** * Token 权限验证工具类 @@ -16,6 +17,24 @@ public static AuthLogic authLogic = new AuthLogic(); /** * 会话注销 */ public static void logout() { authLogic.logout(); } /** * 会话注销,根据指定Token * * @param tokenValue 指定token */ public static void logoutByToken(String token) { authLogic.logoutByToken(token); } /** * 检验当前会话是否已经登录,如未登录,则抛出异常 */ public static void checkLogin() @@ -24,6 +43,22 @@ } /** * 获取当前登录用户信息 */ public static LoginUser getLoginUser(String token) { return authLogic.getLoginUser(token); } /** * 验证当前用户有效期 */ public static void verifyLoginUserExpire(LoginUser loginUser) { authLogic.verifyLoginUserExpire(loginUser); } /** * 当前账号是否含有指定角色标识, 返回true或false * * @param role 角色标识 ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/config/WebMvcConfig.java
New file @@ -0,0 +1,33 @@ package com.ruoyi.common.security.config; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import com.ruoyi.common.security.interceptor.HeaderInterceptor; /** * 拦截器配置 * * @author ruoyi */ public class WebMvcConfig implements WebMvcConfigurer { /** 不需要拦截地址 */ public static final String[] excludeUrls = { "/login", "/logout", "/refresh" }; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(getHeaderInterceptor()) .addPathPatterns("/**") .excludePathPatterns(excludeUrls) .order(-10); } /** * 自定义请求头拦截器 */ public HeaderInterceptor getHeaderInterceptor() { return new HeaderInterceptor(); } } ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/interceptor/HeaderInterceptor.java
New file @@ -0,0 +1,53 @@ package com.ruoyi.common.security.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.AsyncHandlerInterceptor; import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.context.SecurityContextHolder; import com.ruoyi.common.core.utils.ServletUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.security.auth.AuthUtil; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.model.LoginUser; /** * 自定义请求头拦截器,将Header数据封装到线程变量中方便获取 * * @author ruoyi */ public class HeaderInterceptor implements AsyncHandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (!(handler instanceof HandlerMethod)) { return true; } SecurityContextHolder.setUserId(ServletUtils.getHeader(request, SecurityConstants.DETAILS_USER_ID)); SecurityContextHolder.setUserName(ServletUtils.getHeader(request, SecurityConstants.DETAILS_USERNAME)); SecurityContextHolder.setUserKey(ServletUtils.getHeader(request, SecurityConstants.USER_KEY)); String token = SecurityUtils.getToken(); if (StringUtils.isNotEmpty(token)) { LoginUser loginUser = AuthUtil.getLoginUser(token); if (StringUtils.isNotNull(loginUser)) { AuthUtil.verifyLoginUserExpire(loginUser); SecurityContextHolder.set(SecurityConstants.LOGIN_USER, loginUser); } } return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { SecurityContextHolder.remove(); } } ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/service/TokenService.java
@@ -7,13 +7,14 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.constant.Constants; import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.utils.IdUtils; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.JwtUtils; import com.ruoyi.common.core.utils.ServletUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.ip.IpUtils; import com.ruoyi.common.redis.service.RedisService; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.model.LoginUser; /** @@ -27,31 +28,41 @@ @Autowired private RedisService redisService; private final static long EXPIRE_TIME = Constants.TOKEN_EXPIRE * 60; protected static final long MILLIS_SECOND = 1000; protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND; private final static long expireTime = CacheConstants.EXPIRATION; private final static String ACCESS_TOKEN = CacheConstants.LOGIN_TOKEN_KEY; protected static final long MILLIS_SECOND = 1000; private final static Long MILLIS_MINUTE_TEN = CacheConstants.REFRESH_TIME * MILLIS_MINUTE; /** * 创建令牌 */ public Map<String, Object> createToken(LoginUser loginUser) { // 生成token String token = IdUtils.fastUUID(); Long userId = loginUser.getSysUser().getUserId(); String userName = loginUser.getSysUser().getUserName(); loginUser.setToken(token); loginUser.setUserid(loginUser.getSysUser().getUserId()); loginUser.setUsername(loginUser.getSysUser().getUserName()); loginUser.setUserid(userId); loginUser.setUsername(userName); loginUser.setIpaddr(IpUtils.getIpAddr(ServletUtils.getRequest())); refreshToken(loginUser); // 保存或更新用户token Map<String, Object> map = new HashMap<String, Object>(); map.put("access_token", token); map.put("expires_in", EXPIRE_TIME); redisService.setCacheObject(ACCESS_TOKEN + token, loginUser, EXPIRE_TIME, TimeUnit.SECONDS); return map; // Jwt存储信息 Map<String, Object> claimsMap = new HashMap<String, Object>(); claimsMap.put(SecurityConstants.USER_KEY, token); claimsMap.put(SecurityConstants.DETAILS_USER_ID, userId); claimsMap.put(SecurityConstants.DETAILS_USERNAME, userName); // 接口返回信息 Map<String, Object> rspMap = new HashMap<String, Object>(); rspMap.put("access_token", JwtUtils.createToken(claimsMap)); rspMap.put("expires_in", expireTime); return rspMap; } /** @@ -83,13 +94,20 @@ */ public LoginUser getLoginUser(String token) { if (StringUtils.isNotEmpty(token)) LoginUser user = null; try { String userKey = getTokenKey(token); LoginUser user = redisService.getCacheObject(userKey); return user; if (StringUtils.isNotEmpty(token)) { String userkey = JwtUtils.getUserKey(token); user = redisService.getCacheObject(getTokenKey(userkey)); return user; } } return null; catch (Exception e) { } return user; } /** @@ -103,12 +121,30 @@ } } /** * 删除用户缓存信息 */ public void delLoginUser(String token) { if (StringUtils.isNotEmpty(token)) { String userKey = getTokenKey(token); redisService.deleteObject(userKey); String userkey = JwtUtils.getUserKey(token); redisService.deleteObject(getTokenKey(userkey)); } } /** * 验证令牌有效期,相差不足120分钟,自动刷新缓存 * * @param loginUser */ public void verifyToken(LoginUser loginUser) { long expireTime = loginUser.getExpireTime(); long currentTime = System.currentTimeMillis(); if (expireTime - currentTime <= MILLIS_MINUTE_TEN) { refreshToken(loginUser); } } @@ -120,10 +156,10 @@ public void refreshToken(LoginUser loginUser) { loginUser.setLoginTime(System.currentTimeMillis()); loginUser.setExpireTime(loginUser.getLoginTime() + EXPIRE_TIME * MILLIS_SECOND); loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE); // 根据uuid将loginUser缓存 String userKey = getTokenKey(loginUser.getToken()); redisService.setCacheObject(userKey, loginUser, EXPIRE_TIME, TimeUnit.SECONDS); redisService.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES); } private String getTokenKey(String token) ruoyi-common/ruoyi-common-security/src/main/java/com/ruoyi/common/security/utils/SecurityUtils.java
File was renamed from ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SecurityUtils.java @@ -1,9 +1,13 @@ package com.ruoyi.common.core.utils; package com.ruoyi.common.security.utils; import javax.servlet.http.HttpServletRequest; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.text.Convert; import com.ruoyi.common.core.constant.TokenConstants; import com.ruoyi.common.core.context.SecurityContextHolder; import com.ruoyi.common.core.utils.ServletUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.system.api.model.LoginUser; /** * 权限获取工具类 @@ -13,20 +17,35 @@ public class SecurityUtils { /** * 获取用户 */ public static String getUsername() { String username = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USERNAME); return ServletUtils.urlDecode(username); } /** * 获取用户ID */ public static Long getUserId() { return Convert.toLong(ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USER_ID)); return SecurityContextHolder.getUserId(); } /** * 获取用户名称 */ public static String getUsername() { return SecurityContextHolder.getUserName(); } /** * 获取用户key */ public static String getUserKey() { return SecurityContextHolder.getUserKey(); } /** * 获取登录用户信息 */ public static LoginUser getLoginUser() { return SecurityContextHolder.get(SecurityConstants.LOGIN_USER, LoginUser.class); } /** @@ -43,7 +62,7 @@ public static String getToken(HttpServletRequest request) { // 从header获取token标识 String token = request.getHeader(SecurityConstants.TOKEN_AUTHENTICATION); String token = request.getHeader(TokenConstants.AUTHENTICATION); return replaceTokenPrefix(token); } @@ -53,9 +72,9 @@ public static String replaceTokenPrefix(String token) { // 如果前端设置了令牌前缀,则裁剪掉前缀 if (StringUtils.isNotEmpty(token) && token.startsWith(SecurityConstants.TOKEN_PREFIX)) if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX)) { token = token.replaceFirst(SecurityConstants.TOKEN_PREFIX, ""); token = token.replaceFirst(TokenConstants.PREFIX, ""); } return token; } ruoyi-common/ruoyi-common-security/src/main/resources/META-INF/spring.factories
@@ -1,4 +1,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.ruoyi.common.security.config.WebMvcConfig,\ com.ruoyi.common.security.service.TokenService,\ com.ruoyi.common.security.aspect.PreAuthorizeAspect,\ com.ruoyi.common.security.aspect.InnerAuthAspect,\ ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java
@@ -1,26 +1,24 @@ package com.ruoyi.gateway.filter; import javax.annotation.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.data.redis.core.ValueOperations; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import com.alibaba.fastjson.JSONObject; import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.constant.Constants; import com.ruoyi.common.core.constant.HttpStatus; import com.ruoyi.common.core.constant.SecurityConstants; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.constant.TokenConstants; import com.ruoyi.common.core.utils.JwtUtils; import com.ruoyi.common.core.utils.ServletUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.redis.service.RedisService; import com.ruoyi.gateway.config.properties.IgnoreWhiteProperties; import io.jsonwebtoken.Claims; import reactor.core.publisher.Mono; /** @@ -33,17 +31,13 @@ { private static final Logger log = LoggerFactory.getLogger(AuthFilter.class); private final static long EXPIRE_TIME = Constants.TOKEN_EXPIRE * 60; // 排除过滤的 uri 地址,nacos自行添加 @Autowired private IgnoreWhiteProperties ignoreWhite; @Resource(name = "stringRedisTemplate") private ValueOperations<String, String> sops; @Autowired private RedisService redisService; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) @@ -62,22 +56,26 @@ { return unauthorizedResponse(exchange, "令牌不能为空"); } String userStr = sops.get(getTokenKey(token)); if (StringUtils.isEmpty(userStr)) Claims claims = JwtUtils.parseToken(token); if (claims == null) { return unauthorizedResponse(exchange, "token已过期或验证不正确!"); } String userkey = JwtUtils.getUserKey(claims); boolean islogin = redisService.hasKey(getTokenKey(userkey)); if (!islogin) { return unauthorizedResponse(exchange, "登录状态已过期"); } JSONObject cacheObj = JSONObject.parseObject(userStr); String userid = cacheObj.getString("userid"); String username = cacheObj.getString("username"); String userid = JwtUtils.getUserId(claims); String username = JwtUtils.getUserName(claims); if (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username)) { return unauthorizedResponse(exchange, "令牌验证失败"); } // 设置过期时间 redisService.expire(getTokenKey(token), EXPIRE_TIME); // 设置用户信息到请求 addHeader(mutate, SecurityConstants.USER_KEY, userkey); addHeader(mutate, SecurityConstants.DETAILS_USER_ID, userid); addHeader(mutate, SecurityConstants.DETAILS_USERNAME, username); // 内部请求来源参数清除 @@ -120,8 +118,13 @@ */ private String getToken(ServerHttpRequest request) { String token = request.getHeaders().getFirst(SecurityConstants.TOKEN_AUTHENTICATION); return SecurityUtils.replaceTokenPrefix(token); String token = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION); // 如果前端设置了令牌前缀,则裁剪掉前缀 if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX)) { token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY); } return token; } @Override ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableServiceImpl.java
@@ -26,8 +26,8 @@ import com.ruoyi.common.core.constant.GenConstants; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.text.CharsetKit; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.gen.domain.GenTable; import com.ruoyi.gen.domain.GenTableColumn; import com.ruoyi.gen.mapper.GenTableColumnMapper; ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/controller/SysJobController.java
@@ -15,7 +15,6 @@ import org.springframework.web.bind.annotation.RestController; import com.ruoyi.common.core.constant.Constants; import com.ruoyi.common.core.exception.job.TaskException; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.poi.ExcelUtil; import com.ruoyi.common.core.web.controller.BaseController; @@ -24,6 +23,7 @@ import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.job.domain.SysJob; import com.ruoyi.job.service.ISysJobService; import com.ruoyi.job.util.CronUtils; ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysConfigController.java
@@ -14,7 +14,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.poi.ExcelUtil; import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.domain.AjaxResult; @@ -22,6 +21,7 @@ import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.domain.SysConfig; import com.ruoyi.system.service.ISysConfigService; ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDeptController.java
@@ -14,13 +14,13 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.domain.SysDept; import com.ruoyi.system.service.ISysDeptService; ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDictDataController.java
@@ -14,7 +14,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.poi.ExcelUtil; import com.ruoyi.common.core.web.controller.BaseController; @@ -23,6 +22,7 @@ import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.domain.SysDictData; import com.ruoyi.system.service.ISysDictDataService; import com.ruoyi.system.service.ISysDictTypeService; ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDictTypeController.java
@@ -14,7 +14,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.poi.ExcelUtil; import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.domain.AjaxResult; @@ -22,6 +21,7 @@ import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.domain.SysDictType; import com.ruoyi.system.service.ISysDictTypeService; ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysMenuController.java
@@ -12,13 +12,13 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.domain.SysMenu; import com.ruoyi.system.service.ISysMenuService; ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysNoticeController.java
@@ -11,13 +11,13 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.core.web.page.TableDataInfo; import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.domain.SysNotice; import com.ruoyi.system.service.ISysNoticeService; ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysPostController.java
@@ -14,7 +14,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.poi.ExcelUtil; import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.domain.AjaxResult; @@ -22,6 +21,7 @@ import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.domain.SysPost; import com.ruoyi.system.service.ISysPostService; ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysProfileController.java
@@ -12,14 +12,13 @@ import org.springframework.web.multipart.MultipartFile; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.ServletUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.security.service.TokenService; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.RemoteFileService; import com.ruoyi.system.api.domain.SysFile; import com.ruoyi.system.api.domain.SysUser; @@ -75,7 +74,7 @@ { return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); } LoginUser loginUser = tokenService.getLoginUser(); LoginUser loginUser = SecurityUtils.getLoginUser(); SysUser sysUser = loginUser.getSysUser(); user.setUserId(sysUser.getUserId()); user.setPassword(null); @@ -113,7 +112,7 @@ if (userService.resetUserPwd(username, SecurityUtils.encryptPassword(newPassword)) > 0) { // 更新缓存用户密码 LoginUser loginUser = tokenService.getLoginUser(); LoginUser loginUser = SecurityUtils.getLoginUser(); loginUser.getSysUser().setPassword(SecurityUtils.encryptPassword(newPassword)); tokenService.setLoginUser(loginUser); return AjaxResult.success(); @@ -130,7 +129,7 @@ { if (!file.isEmpty()) { LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); LoginUser loginUser = SecurityUtils.getLoginUser(); R<SysFile> fileResult = remoteFileService.upload(file); if (StringUtils.isNull(fileResult) || StringUtils.isNull(fileResult.getData())) { ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysRoleController.java
@@ -14,7 +14,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.poi.ExcelUtil; import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.domain.AjaxResult; @@ -22,6 +21,7 @@ import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.domain.SysRole; import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.domain.SysUserRole; ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java
@@ -19,7 +19,6 @@ import org.springframework.web.multipart.MultipartFile; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.poi.ExcelUtil; import com.ruoyi.common.core.web.controller.BaseController; @@ -29,6 +28,7 @@ import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.security.annotation.InnerAuth; import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.domain.SysRole; import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.api.model.LoginUser; ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
@@ -9,10 +9,10 @@ import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.text.Convert; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.datascope.annotation.DataScope; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.domain.SysDept; import com.ruoyi.system.api.domain.SysRole; import com.ruoyi.system.api.domain.SysUser; ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
@@ -12,8 +12,8 @@ import org.springframework.stereotype.Service; import com.ruoyi.common.core.constant.Constants; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.domain.SysRole; import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.domain.SysMenu; ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
@@ -10,10 +10,10 @@ import org.springframework.transaction.annotation.Transactional; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.datascope.annotation.DataScope; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.domain.SysRole; import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.domain.SysRoleDept; ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
@@ -9,10 +9,10 @@ import org.springframework.transaction.annotation.Transactional; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.utils.SecurityUtils; import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.datascope.annotation.DataScope; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.domain.SysRole; import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.domain.SysPost;