mirror of https://github.com/jeecgboot/jeecg-boot
Merge pull request #5965 from EightMonth/springboot3_sas
新增token校验、客户端便捷工具类、修复登录缺乏租户信息、强退功能失效pull/6161/head
commit
d684c09392
|
@ -1,5 +1,6 @@
|
||||||
package org.jeecg.common.api;
|
package org.jeecg.common.api;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import org.jeecg.common.system.vo.*;
|
import org.jeecg.common.system.vo.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -154,4 +155,11 @@ public interface CommonAPI {
|
||||||
*/
|
*/
|
||||||
void updateUserDepart(String username,String orgCode,Integer loginTenantId);
|
void updateUserDepart(String username,String orgCode,Integer loginTenantId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置登录租户
|
||||||
|
* @param username
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
JSONObject setLoginTenant(String username);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ public interface CommonConstant {
|
||||||
/** 登录用户Shiro权限缓存KEY前缀 */
|
/** 登录用户Shiro权限缓存KEY前缀 */
|
||||||
public static String PREFIX_USER_SHIRO_CACHE = "shiro:cache:org.jeecg.config.shiro.ShiroRealm.authorizationCache:";
|
public static String PREFIX_USER_SHIRO_CACHE = "shiro:cache:org.jeecg.config.shiro.ShiroRealm.authorizationCache:";
|
||||||
/** 登录用户Token令牌缓存KEY前缀 */
|
/** 登录用户Token令牌缓存KEY前缀 */
|
||||||
String PREFIX_USER_TOKEN = "prefix_user_token:";
|
String PREFIX_USER_TOKEN = "token::jeecg-client::";
|
||||||
// /** Token缓存时间:3600秒即一小时 */
|
// /** Token缓存时间:3600秒即一小时 */
|
||||||
// int TOKEN_EXPIRE_TIME = 3600;
|
// int TOKEN_EXPIRE_TIME = 3600;
|
||||||
|
|
||||||
|
|
|
@ -12,13 +12,20 @@ import com.google.common.base.Joiner;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import jakarta.servlet.ServletResponse;
|
import jakarta.servlet.ServletResponse;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import jakarta.servlet.http.HttpSession;
|
import jakarta.servlet.http.HttpSession;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jeecg.common.api.CommonAPI;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.constant.DataBaseConstant;
|
import org.jeecg.common.constant.DataBaseConstant;
|
||||||
|
@ -31,7 +38,17 @@ import org.jeecg.common.util.DateUtils;
|
||||||
import org.jeecg.common.util.SpringContextUtils;
|
import org.jeecg.common.util.SpringContextUtils;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.security.utils.SecureUtil;
|
import org.jeecg.config.security.utils.SecureUtil;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.oauth2.core.*;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author Scott
|
* @Author Scott
|
||||||
|
@ -45,6 +62,8 @@ public class JwtUtil {
|
||||||
public static final long EXPIRE_TIME = (7 * 12) * 60 * 60 * 1000;
|
public static final long EXPIRE_TIME = (7 * 12) * 60 * 60 * 1000;
|
||||||
static final String WELL_NUMBER = SymbolConstant.WELL_NUMBER + SymbolConstant.LEFT_CURLY_BRACKET;
|
static final String WELL_NUMBER = SymbolConstant.WELL_NUMBER + SymbolConstant.LEFT_CURLY_BRACKET;
|
||||||
|
|
||||||
|
public static final String DEFAULT_CLIENT = "jeecg-client";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param response
|
* @param response
|
||||||
|
@ -80,10 +99,9 @@ public class JwtUtil {
|
||||||
public static boolean verify(String token, String username, String secret) {
|
public static boolean verify(String token, String username, String secret) {
|
||||||
try {
|
try {
|
||||||
// 根据密码生成JWT效验器
|
// 根据密码生成JWT效验器
|
||||||
Algorithm algorithm = Algorithm.HMAC256(secret);
|
JwtDecoder jwtDecoder = SpringContextUtils.getBean(JwtDecoder.class);
|
||||||
JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();
|
|
||||||
// 效验TOKEN
|
// 效验TOKEN
|
||||||
DecodedJWT jwt = verifier.verify(token);
|
jwtDecoder.decode(token);
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -98,7 +116,7 @@ public class JwtUtil {
|
||||||
public static String getUsername(String token) {
|
public static String getUsername(String token) {
|
||||||
try {
|
try {
|
||||||
DecodedJWT jwt = JWT.decode(token);
|
DecodedJWT jwt = JWT.decode(token);
|
||||||
LoginUser loginUser = SecureUtil.currentUser();
|
LoginUser loginUser = JSONObject.parseObject(jwt.getClaim("sub").asString(), LoginUser.class);
|
||||||
return loginUser.getUsername();
|
return loginUser.getUsername();
|
||||||
} catch (JWTDecodeException e) {
|
} catch (JWTDecodeException e) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -106,7 +124,7 @@ public class JwtUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成签名,5min后过期
|
* 生成签名,5min后过期(暂未实现)
|
||||||
*
|
*
|
||||||
* @param username 用户名
|
* @param username 用户名
|
||||||
* @param secret 用户的密码
|
* @param secret 用户的密码
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
package org.jeecg.config.security;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||||
|
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spring authorization server 注册客户端便捷工具类
|
||||||
|
* @author eightmonth@qq.com
|
||||||
|
* @date 2024/3/7 11:22
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ClientService {
|
||||||
|
|
||||||
|
private RegisteredClientRepository registeredClientRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改客户端token有效期
|
||||||
|
* 认证码、设备码有效期与accessToken有效期保持一致
|
||||||
|
*/
|
||||||
|
public void updateTokenValidation(String clientId, Long accessTokenValidation, Long refreshTokenValidation){
|
||||||
|
RegisteredClient registeredClient = findByClientId(clientId);
|
||||||
|
RegisteredClient.Builder builder = RegisteredClient.from(registeredClient);
|
||||||
|
TokenSettings tokenSettings = TokenSettings.builder()
|
||||||
|
.idTokenSignatureAlgorithm(SignatureAlgorithm.RS256)
|
||||||
|
.accessTokenTimeToLive(Duration.ofSeconds(accessTokenValidation))
|
||||||
|
.accessTokenFormat(OAuth2TokenFormat.SELF_CONTAINED)
|
||||||
|
.reuseRefreshTokens(true)
|
||||||
|
.refreshTokenTimeToLive(Duration.ofSeconds(refreshTokenValidation))
|
||||||
|
.authorizationCodeTimeToLive(Duration.ofSeconds(accessTokenValidation))
|
||||||
|
.deviceCodeTimeToLive(Duration.ofSeconds(accessTokenValidation))
|
||||||
|
.build();
|
||||||
|
builder.tokenSettings(tokenSettings);
|
||||||
|
registeredClientRepository.save(builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改客户端授权类型
|
||||||
|
* @param clientId
|
||||||
|
* @param grantTypes
|
||||||
|
*/
|
||||||
|
public void updateGrantType(String clientId, Set<AuthorizationGrantType> grantTypes) {
|
||||||
|
RegisteredClient registeredClient = findByClientId(clientId);
|
||||||
|
RegisteredClient.Builder builder = RegisteredClient.from(registeredClient);
|
||||||
|
for (AuthorizationGrantType grantType : grantTypes) {
|
||||||
|
builder.authorizationGrantType(grantType);
|
||||||
|
}
|
||||||
|
registeredClientRepository.save(builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改客户端重定向uri
|
||||||
|
* @param clientId
|
||||||
|
* @param redirectUris
|
||||||
|
*/
|
||||||
|
public void updateRedirectUris(String clientId, String redirectUris) {
|
||||||
|
RegisteredClient registeredClient = findByClientId(clientId);
|
||||||
|
RegisteredClient.Builder builder = RegisteredClient.from(registeredClient);
|
||||||
|
builder.redirectUri(redirectUris);
|
||||||
|
registeredClientRepository.save(builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改客户端授权范围
|
||||||
|
* @param clientId
|
||||||
|
* @param scopes
|
||||||
|
*/
|
||||||
|
public void updateScopes(String clientId, Set<String> scopes) {
|
||||||
|
RegisteredClient registeredClient = findByClientId(clientId);
|
||||||
|
RegisteredClient.Builder builder = RegisteredClient.from(registeredClient);
|
||||||
|
for (String scope : scopes) {
|
||||||
|
builder.scope(scope);
|
||||||
|
}
|
||||||
|
registeredClientRepository.save(builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegisteredClient findByClientId(String clientId) {
|
||||||
|
return registeredClientRepository.findByClientId(clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ import org.springframework.util.StringUtils;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* spring authorization server自定义权限处理,根据@PreAuthorize注解,判断当前用户是否具备权限
|
||||||
* @author EightMonth
|
* @author EightMonth
|
||||||
* @date 2024/1/10 17:00
|
* @date 2024/1/10 17:00
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -9,6 +9,9 @@ import org.springframework.util.Assert;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spring authorization server 自定义redis保存授权范围信息
|
||||||
|
*/
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class JeecgRedisOAuth2AuthorizationConsentService implements OAuth2AuthorizationConsentService {
|
public class JeecgRedisOAuth2AuthorizationConsentService implements OAuth2AuthorizationConsentService {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* spring authorization server自定义redis保存认证信息
|
||||||
* @author EightMonth
|
* @author EightMonth
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package org.jeecg.config.security;
|
||||||
|
|
||||||
|
import jakarta.servlet.FilterChain;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.jeecg.common.system.util.JwtUtil;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
|
||||||
|
import org.springframework.security.oauth2.server.resource.BearerTokenErrors;
|
||||||
|
import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当用户被强退时,使客户端token失效
|
||||||
|
* @author eightmonth@qq.com
|
||||||
|
* @date 2024/3/7 17:30
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class RedisTokenValidationFilter extends OncePerRequestFilter {
|
||||||
|
private OAuth2AuthorizationService authorizationService;
|
||||||
|
private JwtDecoder jwtDecoder;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||||
|
// 从请求中获取token
|
||||||
|
DefaultBearerTokenResolver defaultBearerTokenResolver = new DefaultBearerTokenResolver();
|
||||||
|
String token = defaultBearerTokenResolver.resolve(request);
|
||||||
|
|
||||||
|
|
||||||
|
if (Objects.nonNull(token)) {
|
||||||
|
// 检查认证信息是否已被清除,如果已被清除,则令该token失效
|
||||||
|
OAuth2Authorization oAuth2Authorization = authorizationService.findByToken(token, OAuth2TokenType.ACCESS_TOKEN);
|
||||||
|
if (Objects.isNull(oAuth2Authorization)) {
|
||||||
|
throw new OAuth2AuthenticationException(BearerTokenErrors.invalidToken("认证信息已失效,请重新登录"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,6 +37,7 @@ import org.springframework.security.oauth2.server.authorization.settings.Authori
|
||||||
import org.springframework.security.oauth2.server.authorization.token.*;
|
import org.springframework.security.oauth2.server.authorization.token.*;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
||||||
import org.springframework.web.cors.CorsConfiguration;
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
|
@ -49,6 +50,7 @@ import java.util.Arrays;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* spring authorization server核心配置
|
||||||
* @author eightmonth@qq.com
|
* @author eightmonth@qq.com
|
||||||
* @date 2024/1/2 9:29
|
* @date 2024/1/2 9:29
|
||||||
*/
|
*/
|
||||||
|
@ -66,6 +68,7 @@ public class SecurityConfig {
|
||||||
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http)
|
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
|
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
|
||||||
|
// 注册自定义登录类型
|
||||||
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
|
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
|
||||||
.tokenEndpoint(tokenEndpoint -> tokenEndpoint.accessTokenRequestConverter(new PasswordGrantAuthenticationConvert())
|
.tokenEndpoint(tokenEndpoint -> tokenEndpoint.accessTokenRequestConverter(new PasswordGrantAuthenticationConvert())
|
||||||
.authenticationProvider(new PasswordGrantAuthenticationProvider(authorizationService, tokenGenerator())))
|
.authenticationProvider(new PasswordGrantAuthenticationProvider(authorizationService, tokenGenerator())))
|
||||||
|
@ -172,7 +175,7 @@ public class SecurityConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注册客户端信息
|
* 数据库保存注册客户端信息
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public RegisteredClientRepository registeredClientRepository() {
|
public RegisteredClientRepository registeredClientRepository() {
|
||||||
|
|
|
@ -16,6 +16,7 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* APP模式认证转换器
|
||||||
* @author EightMonth
|
* @author EightMonth
|
||||||
* @date 2024/1/1
|
* @date 2024/1/1
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.jeecg.config.security.app;
|
package org.jeecg.config.security.app;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.common.api.CommonAPI;
|
import org.jeecg.common.api.CommonAPI;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
|
@ -40,6 +41,7 @@ import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* APP模式认证处理器,负责处理该认证模式下的核心逻辑
|
||||||
* @author EightMonth
|
* @author EightMonth
|
||||||
* @date 2024/1/1
|
* @date 2024/1/1
|
||||||
*/
|
*/
|
||||||
|
@ -85,7 +87,7 @@ public class AppGrantAuthenticationProvider implements AuthenticationProvider {
|
||||||
String captcha = (String) additionalParameter.get("captcha");
|
String captcha = (String) additionalParameter.get("captcha");
|
||||||
String checkKey = (String) additionalParameter.get("checkKey");
|
String checkKey = (String) additionalParameter.get("checkKey");
|
||||||
|
|
||||||
|
// 检查登录失败次数
|
||||||
if(isLoginFailOvertimes(username)){
|
if(isLoginFailOvertimes(username)){
|
||||||
throw new JeecgBootException("该用户登录失败次数过多,请于10分钟后再次登录!");
|
throw new JeecgBootException("该用户登录失败次数过多,请于10分钟后再次登录!");
|
||||||
}
|
}
|
||||||
|
@ -112,6 +114,7 @@ public class AppGrantAuthenticationProvider implements AuthenticationProvider {
|
||||||
throw new JeecgBootException("非法登录");
|
throw new JeecgBootException("非法登录");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通过用户名获取用户信息
|
||||||
LoginUser loginUser = commonAPI.getUserByName(username);
|
LoginUser loginUser = commonAPI.getUserByName(username);
|
||||||
// 检查用户可行性
|
// 检查用户可行性
|
||||||
checkUserIsEffective(loginUser);
|
checkUserIsEffective(loginUser);
|
||||||
|
@ -180,6 +183,7 @@ public class AppGrantAuthenticationProvider implements AuthenticationProvider {
|
||||||
|
|
||||||
OAuth2Authorization authorization = authorizationBuilder.build();
|
OAuth2Authorization authorization = authorizationBuilder.build();
|
||||||
|
|
||||||
|
// 保存认证信息至redis
|
||||||
authorizationService.save(authorization);
|
authorizationService.save(authorization);
|
||||||
|
|
||||||
// 登录成功,删除redis中的验证码
|
// 登录成功,删除redis中的验证码
|
||||||
|
@ -187,7 +191,12 @@ public class AppGrantAuthenticationProvider implements AuthenticationProvider {
|
||||||
redisUtil.del(CommonConstant.LOGIN_FAIL + username);
|
redisUtil.del(CommonConstant.LOGIN_FAIL + username);
|
||||||
baseCommonService.addLog("用户名: " + username + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
|
baseCommonService.addLog("用户名: " + username + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
|
||||||
|
|
||||||
Map<String, Object> addition = new HashMap<>();
|
JSONObject addition = new JSONObject(new LinkedHashMap<>());
|
||||||
|
|
||||||
|
// 设置租户
|
||||||
|
JSONObject jsonObject = commonAPI.setLoginTenant(username);
|
||||||
|
addition.putAll(jsonObject.getInnerMap());
|
||||||
|
|
||||||
// 设置登录用户信息
|
// 设置登录用户信息
|
||||||
addition.put("userInfo", loginUser);
|
addition.put("userInfo", loginUser);
|
||||||
addition.put("sysAllDictItems", commonAPI.queryAllDictItems());
|
addition.put("sysAllDictItems", commonAPI.queryAllDictItems());
|
||||||
|
@ -207,6 +216,7 @@ public class AppGrantAuthenticationProvider implements AuthenticationProvider {
|
||||||
addition.put("multi_depart", 2);
|
addition.put("multi_depart", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 返回access_token、refresh_token以及其它信息给到前端
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, addition);
|
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, addition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import org.springframework.security.oauth2.server.authorization.authentication.O
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* APP模式认证专用token类型,方法spring authorization server进行认证流转,配合convert使用
|
||||||
* @author EightMonth
|
* @author EightMonth
|
||||||
* @date 2024/1/1
|
* @date 2024/1/1
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -17,6 +17,7 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 密码模式认证转换器
|
||||||
* @author EightMonth
|
* @author EightMonth
|
||||||
* @date 2024/1/1
|
* @date 2024/1/1
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.jeecg.config.security.password;
|
package org.jeecg.config.security.password;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.common.api.CommonAPI;
|
import org.jeecg.common.api.CommonAPI;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
|
@ -41,6 +42,7 @@ import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 密码模式认证处理器,负责处理该认证模式下的核心逻辑
|
||||||
* @author EightMonth
|
* @author EightMonth
|
||||||
* @date 2024/1/1
|
* @date 2024/1/1
|
||||||
*/
|
*/
|
||||||
|
@ -86,7 +88,7 @@ public class PasswordGrantAuthenticationProvider implements AuthenticationProvid
|
||||||
String captcha = (String) additionalParameter.get("captcha");
|
String captcha = (String) additionalParameter.get("captcha");
|
||||||
String checkKey = (String) additionalParameter.get("checkKey");
|
String checkKey = (String) additionalParameter.get("checkKey");
|
||||||
|
|
||||||
|
// 检查登录失败次数
|
||||||
if(isLoginFailOvertimes(username)){
|
if(isLoginFailOvertimes(username)){
|
||||||
throw new JeecgBootException("该用户登录失败次数过多,请于10分钟后再次登录!");
|
throw new JeecgBootException("该用户登录失败次数过多,请于10分钟后再次登录!");
|
||||||
}
|
}
|
||||||
|
@ -113,6 +115,7 @@ public class PasswordGrantAuthenticationProvider implements AuthenticationProvid
|
||||||
throw new JeecgBootException("非法登录");
|
throw new JeecgBootException("非法登录");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通过用户名获取用户信息
|
||||||
LoginUser loginUser = commonAPI.getUserByName(username);
|
LoginUser loginUser = commonAPI.getUserByName(username);
|
||||||
// 检查用户可行性
|
// 检查用户可行性
|
||||||
checkUserIsEffective(loginUser);
|
checkUserIsEffective(loginUser);
|
||||||
|
@ -181,6 +184,7 @@ public class PasswordGrantAuthenticationProvider implements AuthenticationProvid
|
||||||
|
|
||||||
OAuth2Authorization authorization = authorizationBuilder.build();
|
OAuth2Authorization authorization = authorizationBuilder.build();
|
||||||
|
|
||||||
|
// 保存认证信息至redis
|
||||||
authorizationService.save(authorization);
|
authorizationService.save(authorization);
|
||||||
|
|
||||||
// 登录成功,删除redis中的验证码
|
// 登录成功,删除redis中的验证码
|
||||||
|
@ -188,7 +192,12 @@ public class PasswordGrantAuthenticationProvider implements AuthenticationProvid
|
||||||
redisUtil.del(CommonConstant.LOGIN_FAIL + username);
|
redisUtil.del(CommonConstant.LOGIN_FAIL + username);
|
||||||
baseCommonService.addLog("用户名: " + username + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
|
baseCommonService.addLog("用户名: " + username + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
|
||||||
|
|
||||||
Map<String, Object> addition = new HashMap<>();
|
JSONObject addition = new JSONObject(new LinkedHashMap<>());
|
||||||
|
|
||||||
|
// 设置租户
|
||||||
|
JSONObject jsonObject = commonAPI.setLoginTenant(username);
|
||||||
|
addition.putAll(jsonObject.getInnerMap());
|
||||||
|
|
||||||
// 设置登录用户信息
|
// 设置登录用户信息
|
||||||
addition.put("userInfo", loginUser);
|
addition.put("userInfo", loginUser);
|
||||||
addition.put("sysAllDictItems", commonAPI.queryAllDictItems());
|
addition.put("sysAllDictItems", commonAPI.queryAllDictItems());
|
||||||
|
@ -208,6 +217,7 @@ public class PasswordGrantAuthenticationProvider implements AuthenticationProvid
|
||||||
addition.put("multi_depart", 2);
|
addition.put("multi_depart", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 返回access_token、refresh_token以及其它信息给到前端
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, addition);
|
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, addition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import org.springframework.security.oauth2.server.authorization.authentication.O
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 密码模式认证专用token类型,方法spring authorization server进行认证流转,配合convert使用
|
||||||
* @author EightMonth
|
* @author EightMonth
|
||||||
* @date 2024/1/1
|
* @date 2024/1/1
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -16,6 +16,7 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 手机号模式认证转换器
|
||||||
* @author EightMonth
|
* @author EightMonth
|
||||||
* @date 2024/1/1
|
* @date 2024/1/1
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.jeecg.config.security.phone;
|
package org.jeecg.config.security.phone;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.common.api.CommonAPI;
|
import org.jeecg.common.api.CommonAPI;
|
||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
|
@ -40,6 +41,7 @@ import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 手机号模式认证处理器,负责处理该认证模式下的核心逻辑
|
||||||
* @author EightMonth
|
* @author EightMonth
|
||||||
* @date 2024/1/1
|
* @date 2024/1/1
|
||||||
*/
|
*/
|
||||||
|
@ -87,6 +89,7 @@ public class PhoneGrantAuthenticationProvider implements AuthenticationProvider
|
||||||
// 验证码
|
// 验证码
|
||||||
String captcha = (String) additionalParameter.get("captcha");
|
String captcha = (String) additionalParameter.get("captcha");
|
||||||
|
|
||||||
|
// 通过手机号获取用户信息
|
||||||
LoginUser loginUser = commonAPI.getUserByPhone(phone);
|
LoginUser loginUser = commonAPI.getUserByPhone(phone);
|
||||||
// 检查用户可行性
|
// 检查用户可行性
|
||||||
checkUserIsEffective(loginUser);
|
checkUserIsEffective(loginUser);
|
||||||
|
@ -166,11 +169,17 @@ public class PhoneGrantAuthenticationProvider implements AuthenticationProvider
|
||||||
|
|
||||||
OAuth2Authorization authorization = authorizationBuilder.build();
|
OAuth2Authorization authorization = authorizationBuilder.build();
|
||||||
|
|
||||||
|
// 保存认证信息至redis
|
||||||
authorizationService.save(authorization);
|
authorizationService.save(authorization);
|
||||||
|
|
||||||
baseCommonService.addLog("用户名: " + loginUser.getUsername() + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
|
baseCommonService.addLog("用户名: " + loginUser.getUsername() + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
|
||||||
|
|
||||||
Map<String, Object> addition = new HashMap<>();
|
JSONObject addition = new JSONObject(new LinkedHashMap<>());
|
||||||
|
|
||||||
|
// 设置租户
|
||||||
|
JSONObject jsonObject = commonAPI.setLoginTenant(loginUser.getUsername());
|
||||||
|
addition.putAll(jsonObject.getInnerMap());
|
||||||
|
|
||||||
// 设置登录用户信息
|
// 设置登录用户信息
|
||||||
addition.put("userInfo", loginUser);
|
addition.put("userInfo", loginUser);
|
||||||
addition.put("sysAllDictItems", commonAPI.queryAllDictItems());
|
addition.put("sysAllDictItems", commonAPI.queryAllDictItems());
|
||||||
|
@ -190,6 +199,7 @@ public class PhoneGrantAuthenticationProvider implements AuthenticationProvider
|
||||||
addition.put("multi_depart", 2);
|
addition.put("multi_depart", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 返回access_token、refresh_token以及其它信息给到前端
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, addition);
|
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, addition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import org.springframework.security.oauth2.server.authorization.authentication.O
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 手机号模式认证专用token类型,方法spring authorization server进行认证流转,配合convert使用
|
||||||
* @author EightMonth
|
* @author EightMonth
|
||||||
* @date 2024/1/1
|
* @date 2024/1/1
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -16,6 +16,7 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 社交模式认证转换器,配合github、企业微信、钉钉、微信登录使用
|
||||||
* @author EightMonth
|
* @author EightMonth
|
||||||
* @date 2024/1/1
|
* @date 2024/1/1
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.jeecg.config.security.social;
|
package org.jeecg.config.security.social;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.auth0.jwt.JWT;
|
import com.auth0.jwt.JWT;
|
||||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
@ -38,6 +39,7 @@ import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 社交模式认证处理器,负责处理该认证模式下的核心逻辑,配合github、企业微信、钉钉、微信登录使用
|
||||||
* @author EightMonth
|
* @author EightMonth
|
||||||
* @date 2024/1/1
|
* @date 2024/1/1
|
||||||
*/
|
*/
|
||||||
|
@ -84,6 +86,7 @@ public class SocialGrantAuthenticationProvider implements AuthenticationProvider
|
||||||
DecodedJWT jwt = JWT.decode(token);
|
DecodedJWT jwt = JWT.decode(token);
|
||||||
String username = jwt.getClaim("username").asString();
|
String username = jwt.getClaim("username").asString();
|
||||||
|
|
||||||
|
// 通过手机号获取用户信息
|
||||||
LoginUser loginUser = commonAPI.getUserByName(username);
|
LoginUser loginUser = commonAPI.getUserByName(username);
|
||||||
// 检查用户可行性
|
// 检查用户可行性
|
||||||
checkUserIsEffective(loginUser);
|
checkUserIsEffective(loginUser);
|
||||||
|
@ -152,11 +155,17 @@ public class SocialGrantAuthenticationProvider implements AuthenticationProvider
|
||||||
|
|
||||||
OAuth2Authorization authorization = authorizationBuilder.build();
|
OAuth2Authorization authorization = authorizationBuilder.build();
|
||||||
|
|
||||||
|
// 保存认证信息至redis
|
||||||
authorizationService.save(authorization);
|
authorizationService.save(authorization);
|
||||||
|
|
||||||
baseCommonService.addLog("用户名: " + loginUser.getUsername() + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
|
baseCommonService.addLog("用户名: " + loginUser.getUsername() + ",登录成功!", CommonConstant.LOG_TYPE_1, null,loginUser);
|
||||||
|
|
||||||
Map<String, Object> addition = new HashMap<>();
|
JSONObject addition = new JSONObject(new LinkedHashMap<>());
|
||||||
|
|
||||||
|
// 设置租户
|
||||||
|
JSONObject jsonObject = commonAPI.setLoginTenant(loginUser.getUsername());
|
||||||
|
addition.putAll(jsonObject.getInnerMap());
|
||||||
|
|
||||||
// 设置登录用户信息
|
// 设置登录用户信息
|
||||||
addition.put("userInfo", loginUser);
|
addition.put("userInfo", loginUser);
|
||||||
addition.put("sysAllDictItems", commonAPI.queryAllDictItems());
|
addition.put("sysAllDictItems", commonAPI.queryAllDictItems());
|
||||||
|
@ -176,6 +185,7 @@ public class SocialGrantAuthenticationProvider implements AuthenticationProvider
|
||||||
addition.put("multi_depart", 2);
|
addition.put("multi_depart", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 返回access_token、refresh_token以及其它信息给到前端
|
||||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, addition);
|
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, addition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import org.springframework.security.oauth2.server.authorization.authentication.O
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 社交模式认证专用token类型,方法spring authorization server进行认证流转,配合convert使用,配合github、企业微信、钉钉、微信登录使用
|
||||||
* @author EightMonth
|
* @author EightMonth
|
||||||
* @date 2024/1/1
|
* @date 2024/1/1
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2,14 +2,20 @@ package org.jeecg.config.security.utils;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
|
import org.jeecg.common.util.SpringContextUtils;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 认证信息工具类
|
||||||
* @author EightMonth
|
* @author EightMonth
|
||||||
* @date 2024/1/10 17:03
|
* @date 2024/1/10 17:03
|
||||||
*/
|
*/
|
||||||
public class SecureUtil {
|
public class SecureUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过当前认证信息获取用户信息
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public static LoginUser currentUser() {
|
public static LoginUser currentUser() {
|
||||||
String name = SecurityContextHolder.getContext().getAuthentication().getName();
|
String name = SecurityContextHolder.getContext().getAuthentication().getName();
|
||||||
return JSONObject.parseObject(name, LoginUser.class);
|
return JSONObject.parseObject(name, LoginUser.class);
|
||||||
|
|
|
@ -749,4 +749,6 @@ public interface ISysBaseAPI extends CommonAPI {
|
||||||
@PostMapping("/sys/api/updateUserDepart")
|
@PostMapping("/sys/api/updateUserDepart")
|
||||||
void updateUserDepart(@RequestParam("username") String username,@RequestParam("orgCode") String orgCode,@RequestParam("loginTenantId") Integer loginTenantId);
|
void updateUserDepart(@RequestParam("username") String username,@RequestParam("orgCode") String orgCode,@RequestParam("loginTenantId") Integer loginTenantId);
|
||||||
|
|
||||||
|
@GetMapping("/sys/api/setLoginTenant")
|
||||||
|
JSONObject setLoginTenant(@RequestParam("username") String username);
|
||||||
}
|
}
|
||||||
|
|
|
@ -452,4 +452,9 @@ public class SysBaseAPIFallback implements ISysBaseAPI {
|
||||||
public LoginUser getUserByPhone(String phone) {
|
public LoginUser getUserByPhone(String phone) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject setLoginTenant(String username) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -917,4 +917,9 @@ public class SystemApiController {
|
||||||
sysBaseApi.updateUserDepart(username, orgCode, loginTenantId);
|
sysBaseApi.updateUserDepart(username, orgCode, loginTenantId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/sys/api/setLoginTenant")
|
||||||
|
public JSONObject setLoginTenant(@RequestParam("username") String username) {
|
||||||
|
return sysBaseApi.setLoginTenant(username);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.jeecg.common.api.dto.DataLogDTO;
|
import org.jeecg.common.api.dto.DataLogDTO;
|
||||||
import org.jeecg.common.api.dto.OnlineAuthDTO;
|
import org.jeecg.common.api.dto.OnlineAuthDTO;
|
||||||
import org.jeecg.common.api.dto.message.*;
|
import org.jeecg.common.api.dto.message.*;
|
||||||
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.aspect.UrlMatchEnum;
|
import org.jeecg.common.aspect.UrlMatchEnum;
|
||||||
import org.jeecg.common.config.TenantContext;
|
import org.jeecg.common.config.TenantContext;
|
||||||
import org.jeecg.common.constant.*;
|
import org.jeecg.common.constant.*;
|
||||||
|
@ -1780,4 +1781,11 @@ public class SysBaseApiImpl implements ISysBaseAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject setLoginTenant(String username) {
|
||||||
|
JSONObject obj = new JSONObject(new LinkedHashMap<>());
|
||||||
|
SysUser sysUser = sysUserService.getUserByName(username);
|
||||||
|
sysUserService.setLoginTenant(sysUser, obj, username, null);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue