mirror of
https://gitee.com/dromara/RuoYi-Cloud-Plus.git
synced 2025-09-07 04:50:38 +00:00
!15 合并 新功能/satoken 分支
This commit is contained in:
@@ -29,12 +29,6 @@
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Transmittable ThreadLocal -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>transmittable-thread-local</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
@@ -111,11 +105,6 @@
|
||||
<artifactId>hutool-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-jwt</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
|
@@ -1,23 +1,40 @@
|
||||
package com.ruoyi.common.core.constant;
|
||||
|
||||
/**
|
||||
* 缓存的key 常量
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface CacheConstants {
|
||||
/**
|
||||
* 缓存有效期,默认720(分钟)
|
||||
*/
|
||||
long EXPIRATION = 720;
|
||||
|
||||
/**
|
||||
* 缓存刷新时间,默认120(分钟)
|
||||
*/
|
||||
long REFRESH_TIME = 120;
|
||||
|
||||
/**
|
||||
* 权限缓存前缀
|
||||
*/
|
||||
String LOGIN_TOKEN_KEY = "login_tokens:";
|
||||
}
|
||||
package com.ruoyi.common.core.constant;
|
||||
|
||||
/**
|
||||
* 缓存的key 常量
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface CacheConstants {
|
||||
|
||||
/**
|
||||
* 登录用户 redis key
|
||||
*/
|
||||
String LOGIN_TOKEN_KEY = "Authorization:login:token:";
|
||||
|
||||
/**
|
||||
* 在线用户 redis key
|
||||
*/
|
||||
String ONLINE_TOKEN_KEY = "online_tokens:";
|
||||
|
||||
/**
|
||||
* loginid构造拼接字符串
|
||||
*/
|
||||
String LOGINID_JOIN_CODE = ":";
|
||||
|
||||
/**
|
||||
* 登陆错误 redis key
|
||||
*/
|
||||
String LOGIN_ERROR = "login_error:";
|
||||
|
||||
/**
|
||||
* 登录错误次数
|
||||
*/
|
||||
Integer LOGIN_ERROR_NUMBER = 5;
|
||||
|
||||
/**
|
||||
* 登录错误限制时间(分钟)
|
||||
*/
|
||||
Integer LOGIN_ERROR_LIMIT_TIME = 10;
|
||||
|
||||
}
|
||||
|
@@ -1,75 +0,0 @@
|
||||
package com.ruoyi.common.core.context;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 获取当前线程变量中的 用户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,27 @@
|
||||
package com.ruoyi.common.core.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
* 针对一套 用户体系
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DeviceType {
|
||||
|
||||
/**
|
||||
* pc端
|
||||
*/
|
||||
PC("pc"),
|
||||
|
||||
/**
|
||||
* app端
|
||||
*/
|
||||
APP("app");
|
||||
|
||||
private final String device;
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
package com.ruoyi.common.core.enums;
|
||||
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
* 针对多套 用户体系
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum UserType {
|
||||
|
||||
/**
|
||||
* pc端
|
||||
*/
|
||||
SYS_USER("sys_user"),
|
||||
|
||||
/**
|
||||
* app端
|
||||
*/
|
||||
APP_USER("app_user");
|
||||
|
||||
private final String userType;
|
||||
|
||||
public static UserType getUserType(String str) {
|
||||
for (UserType value : values()) {
|
||||
if (StringUtils.contains(str, value.getUserType())) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("'UserType' not found By " + str);
|
||||
}
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
package com.ruoyi.common.core.exception;
|
||||
|
||||
/**
|
||||
* 内部认证异常
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class InnerAuthException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InnerAuthException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
package com.ruoyi.common.core.exception;
|
||||
|
||||
/**
|
||||
* 权限异常
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class PreAuthorizeException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public PreAuthorizeException() {
|
||||
}
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
package com.ruoyi.common.core.exception.auth;
|
||||
|
||||
/**
|
||||
* 未能通过的登录认证异常
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class NotLoginException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public NotLoginException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
package com.ruoyi.common.core.exception.auth;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* 未能通过的权限认证异常
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class NotPermissionException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public NotPermissionException(String permission) {
|
||||
super(permission);
|
||||
}
|
||||
|
||||
public NotPermissionException(String[] permissions) {
|
||||
super(StringUtils.join(permissions, ","));
|
||||
}
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
package com.ruoyi.common.core.exception.auth;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* 未能通过的角色认证异常
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class NotRoleException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public NotRoleException(String role) {
|
||||
super(role);
|
||||
}
|
||||
|
||||
public NotRoleException(String[] roles) {
|
||||
super(StringUtils.join(roles, ","));
|
||||
}
|
||||
}
|
@@ -1,16 +1,16 @@
|
||||
package com.ruoyi.common.core.exception.user;
|
||||
|
||||
import com.ruoyi.common.core.exception.base.BaseException;
|
||||
|
||||
/**
|
||||
* 用户信息异常类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class UserException extends BaseException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public UserException(String code, Object[] args) {
|
||||
super("user", code, args, null);
|
||||
}
|
||||
}
|
||||
package com.ruoyi.common.core.exception.user;
|
||||
|
||||
import com.ruoyi.common.core.exception.base.BaseException;
|
||||
|
||||
/**
|
||||
* 用户信息异常类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class UserException extends BaseException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public UserException(String code, Object[] args) {
|
||||
super("user", code, args, null);
|
||||
}
|
||||
}
|
||||
|
@@ -1,117 +0,0 @@
|
||||
package com.ruoyi.common.core.utils;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.jwt.JWTUtil;
|
||||
import cn.hutool.jwt.signers.JWTSigner;
|
||||
import cn.hutool.jwt.signers.JWTSignerUtil;
|
||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
||||
import com.ruoyi.common.core.constant.TokenConstants;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Jwt工具类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class JwtUtils {
|
||||
public static String secret = TokenConstants.SECRET;
|
||||
|
||||
/**
|
||||
* 从数据声明生成令牌
|
||||
*
|
||||
* @param claims 数据声明
|
||||
* @return 令牌
|
||||
*/
|
||||
public static String createToken(Map<String, Object> claims) {
|
||||
JWTSigner signer = JWTSignerUtil.hs512(secret.getBytes());
|
||||
String token = JWTUtil.createToken(claims, signer);
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从令牌中获取数据声明
|
||||
*
|
||||
* @param token 令牌
|
||||
* @return 数据声明
|
||||
*/
|
||||
public static JSONObject parseToken(String token) {
|
||||
JWTSigner signer = JWTSignerUtil.hs512(secret.getBytes());
|
||||
return JWTUtil.parseToken(token).setSigner(signer).getPayload().getClaimsJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据令牌获取用户标识
|
||||
*
|
||||
* @param token 令牌
|
||||
* @return 用户ID
|
||||
*/
|
||||
public static String getUserKey(String token) {
|
||||
JSONObject claims = parseToken(token);
|
||||
return getValue(claims, SecurityConstants.USER_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据令牌获取用户标识
|
||||
*
|
||||
* @param claims 身份信息
|
||||
* @return 用户ID
|
||||
*/
|
||||
public static String getUserKey(JSONObject claims) {
|
||||
return getValue(claims, SecurityConstants.USER_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据令牌获取用户ID
|
||||
*
|
||||
* @param token 令牌
|
||||
* @return 用户ID
|
||||
*/
|
||||
public static String getUserId(String token) {
|
||||
JSONObject claims = parseToken(token);
|
||||
return getValue(claims, SecurityConstants.DETAILS_USER_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据身份信息获取用户ID
|
||||
*
|
||||
* @param claims 身份信息
|
||||
* @return 用户ID
|
||||
*/
|
||||
public static String getUserId(JSONObject claims) {
|
||||
return getValue(claims, SecurityConstants.DETAILS_USER_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据令牌获取用户名
|
||||
*
|
||||
* @param token 令牌
|
||||
* @return 用户名
|
||||
*/
|
||||
public static String getUserName(String token) {
|
||||
JSONObject claims = parseToken(token);
|
||||
return getValue(claims, SecurityConstants.DETAILS_USERNAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据身份信息获取用户名
|
||||
*
|
||||
* @param claims 身份信息
|
||||
* @return 用户名
|
||||
*/
|
||||
public static String getUserName(JSONObject claims) {
|
||||
return getValue(claims, SecurityConstants.DETAILS_USERNAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据身份信息获取键值
|
||||
*
|
||||
* @param claims 身份信息
|
||||
* @param key 键
|
||||
* @return 值
|
||||
*/
|
||||
public static String getValue(JSONObject claims, String key) {
|
||||
return Convert.toStr(claims.get(key), "");
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
package com.ruoyi.common.core.utils.ip;
|
||||
|
||||
import cn.hutool.core.net.NetUtil;
|
||||
import cn.hutool.http.HtmlUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.ruoyi.common.core.constant.Constants;
|
||||
import com.ruoyi.common.core.utils.JsonUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 获取地址类
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Slf4j
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class AddressUtils {
|
||||
|
||||
// IP地址查询
|
||||
public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp";
|
||||
|
||||
// 未知地址
|
||||
public static final String UNKNOWN = "XX XX";
|
||||
|
||||
public static String getRealAddressByIP(String ip) {
|
||||
String address = UNKNOWN;
|
||||
if (StringUtils.isBlank(ip)) {
|
||||
return address;
|
||||
}
|
||||
// 内网不查询
|
||||
ip = "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : HtmlUtil.cleanHtmlTag(ip);
|
||||
if (NetUtil.isInnerIP(ip)) {
|
||||
return "内网IP";
|
||||
}
|
||||
// if (RuoYiConfig.isAddressEnabled()) {
|
||||
try {
|
||||
String rspStr = HttpUtil.createGet(IP_URL)
|
||||
.body("ip=" + ip + "&json=true", Constants.GBK)
|
||||
.execute()
|
||||
.body();
|
||||
if (StringUtils.isEmpty(rspStr)) {
|
||||
log.error("获取地理位置异常 {}", ip);
|
||||
return UNKNOWN;
|
||||
}
|
||||
Map<String, String> obj = JsonUtils.parseMap(rspStr);
|
||||
String region = obj.get("pro");
|
||||
String city = obj.get("city");
|
||||
return String.format("%s %s", region, city);
|
||||
} catch (Exception e) {
|
||||
log.error("获取地理位置异常 {}", ip);
|
||||
}
|
||||
// }
|
||||
return address;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user