40 changed files with 715 additions and 192 deletions
@ -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"; |
||||||
|
|
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
@ -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), ""); |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue