init
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.auth;
|
||||
|
||||
|
||||
import org.springblade.core.cloud.client.BladeCloudApplication;
|
||||
import org.springblade.core.launch.BladeApplication;
|
||||
import org.springblade.core.launch.constant.AppConstant;
|
||||
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
|
||||
|
||||
/**
|
||||
* 用户认证服务器
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@EnableRedisHttpSession
|
||||
@BladeCloudApplication
|
||||
public class AuthApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
BladeApplication.run(AppConstant.APPLICATION_AUTH_NAME, AuthApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.auth.config;
|
||||
|
||||
import org.springblade.auth.handler.BladeAuthorizationHandler;
|
||||
import org.springblade.auth.handler.BladeLockHandler;
|
||||
import org.springblade.auth.handler.BladeLogHandler;
|
||||
import org.springblade.auth.handler.BladePasswordHandler;
|
||||
import org.springblade.auth.handler.BladeTokenHandler;
|
||||
import org.springblade.auth.service.BladeClientDetailService;
|
||||
import org.springblade.auth.service.BladeUserDetailService;
|
||||
import org.springblade.core.jwt.props.JwtProperties;
|
||||
import org.springblade.core.launch.props.BladeProperties;
|
||||
import org.springblade.core.launch.server.ServerInfo;
|
||||
import org.springblade.core.oauth2.config.OAuth2AutoConfiguration;
|
||||
import org.springblade.core.oauth2.handler.AuthorizationHandler;
|
||||
import org.springblade.core.oauth2.handler.PasswordHandler;
|
||||
import org.springblade.core.oauth2.handler.TokenHandler;
|
||||
import org.springblade.core.oauth2.props.OAuth2Properties;
|
||||
import org.springblade.core.oauth2.service.OAuth2ClientService;
|
||||
import org.springblade.core.oauth2.service.OAuth2UserService;
|
||||
import org.springblade.system.feign.IAuthLockClient;
|
||||
import org.springblade.system.feign.IAuthLogClient;
|
||||
import org.springblade.core.tenant.BladeTenantProperties;
|
||||
import org.springblade.system.feign.IUserClient;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
/**
|
||||
* BladeAuthConfiguration
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@AutoConfigureBefore(OAuth2AutoConfiguration.class)
|
||||
public class BladeAuthConfiguration {
|
||||
@Bean
|
||||
public AuthorizationHandler authorizationHandler(BladeProperties bladeProperties,
|
||||
BladeTenantProperties tenantProperties,
|
||||
OAuth2Properties oAuth2Properties,
|
||||
BladeLockHandler lockHandler,
|
||||
BladeLogHandler logHandler) {
|
||||
return new BladeAuthorizationHandler(bladeProperties, tenantProperties, oAuth2Properties, lockHandler, logHandler);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BladeLockHandler lockHandler(IAuthLockClient authLockClient) {
|
||||
return new BladeLockHandler(authLockClient);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BladeLogHandler logHandler(IAuthLogClient authLogClient, BladeProperties bladeProperties, ServerInfo serverInfo) {
|
||||
return new BladeLogHandler(authLogClient, bladeProperties, serverInfo);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordHandler passwordHandler(OAuth2Properties properties) {
|
||||
return new BladePasswordHandler(properties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TokenHandler tokenHandler(JwtProperties jwtProperties) {
|
||||
return new BladeTokenHandler(jwtProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OAuth2ClientService oAuth2ClientService(JdbcTemplate jdbcTemplate) {
|
||||
return new BladeClientDetailService(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OAuth2UserService oAuth2UserService(IUserClient userClient) {
|
||||
return new BladeUserDetailService(userClient);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.auth.constant;
|
||||
|
||||
/**
|
||||
* AuthorizationConstant
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface BladeAuthConstant {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.auth.endpoint;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springblade.core.oauth2.props.OAuth2Properties;
|
||||
import org.springblade.core.oauth2.provider.OAuth2Request;
|
||||
import org.springblade.core.oauth2.service.OAuth2User;
|
||||
import org.springblade.core.oauth2.service.OAuth2UserService;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.core.tool.utils.SM2Util;
|
||||
import org.springblade.core.tool.utils.StringPool;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.resource.feign.ISmsClient;
|
||||
import org.springblade.resource.utils.SmsUtil;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.springblade.core.oauth2.constant.OAuth2TokenConstant.USER_PHONE_NOT_FOUND;
|
||||
|
||||
/**
|
||||
* Oauth2SmsEndpoint
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
@Tag(name = "用户短信认证", description = "4 - OAuth2短信认证端点")
|
||||
public class Oauth2SmsEndpoint {
|
||||
|
||||
/**
|
||||
* 短信服务构建类
|
||||
*/
|
||||
private final ISmsClient smsClient;
|
||||
|
||||
/**
|
||||
* 用户服务类
|
||||
*/
|
||||
private final OAuth2UserService userService;
|
||||
|
||||
/**
|
||||
* OAuth2配置类
|
||||
*/
|
||||
private final OAuth2Properties properties;
|
||||
|
||||
/**
|
||||
* 短信验证码发送
|
||||
*
|
||||
* @param tenantId 租户ID
|
||||
* @param phone 手机号
|
||||
*/
|
||||
@SneakyThrows
|
||||
@PostMapping("/oauth/sms/send-validate")
|
||||
public R sendValidate(@RequestParam String tenantId, @RequestParam String phone) {
|
||||
// 校验手机加密认证,防止恶意发送验证码
|
||||
String decryptedPhone = SM2Util.decrypt(phone, properties.getPublicKey(), properties.getPrivateKey());
|
||||
if (StringUtil.isBlank(decryptedPhone)) {
|
||||
return R.fail(USER_PHONE_NOT_FOUND);
|
||||
}
|
||||
// 校验手机是否已注册,防止恶意发送验证码
|
||||
OAuth2Request request = OAuth2Request.create();
|
||||
request.setTenantId(tenantId);
|
||||
OAuth2User oAuth2User = userService.loadByPhone(decryptedPhone, request);
|
||||
if (oAuth2User == null) {
|
||||
return R.fail(USER_PHONE_NOT_FOUND);
|
||||
}
|
||||
// 用户存在则发送验证码
|
||||
R result = smsClient.sendValidate(tenantId, StringPool.EMPTY, decryptedPhone);
|
||||
return result.isSuccess() ? R.data(result.getData(), SmsUtil.SEND_SUCCESS) : R.fail(SmsUtil.SEND_FAIL);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.auth.granter;
|
||||
|
||||
import org.springblade.core.oauth2.constant.OAuth2TokenConstant;
|
||||
import org.springblade.core.oauth2.exception.UserInvalidException;
|
||||
import org.springblade.core.oauth2.granter.PasswordTokenGranter;
|
||||
import org.springblade.core.oauth2.handler.PasswordHandler;
|
||||
import org.springblade.core.oauth2.provider.OAuth2Request;
|
||||
import org.springblade.core.oauth2.service.OAuth2ClientService;
|
||||
import org.springblade.core.oauth2.service.OAuth2User;
|
||||
import org.springblade.core.oauth2.service.OAuth2UserService;
|
||||
import org.springblade.core.redis.cache.BladeRedis;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* BehaviorTokenGranter
|
||||
*
|
||||
* <p>行为验证码授权模式。行为验证(点选/滑块/旋转)在专用端点完成并换取一次性通行票据,
|
||||
* 登录请求经由验证码请求头携带票据,本授权器核销票据后进入密码认证链路。</p>
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Component
|
||||
public class BehaviorTokenGranter extends PasswordTokenGranter {
|
||||
|
||||
private final BladeRedis bladeRedis;
|
||||
|
||||
public BehaviorTokenGranter(OAuth2ClientService clientService, OAuth2UserService userService, PasswordHandler passwordHandler, BladeRedis bladeRedis) {
|
||||
super(clientService, userService, passwordHandler);
|
||||
this.bladeRedis = bladeRedis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return BEHAVIOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2User user(OAuth2Request request) {
|
||||
// 获取行为验证票据信息
|
||||
String key = request.getCaptchaKey();
|
||||
String ticket = request.getCaptchaCode();
|
||||
// 票据一次性核销,防止同一票据重复登录
|
||||
String cacheTicket = bladeRedis.getAndDel(OAuth2TokenConstant.BEHAVIOR_TICKET_KEY + key);
|
||||
// 判断票据有效性
|
||||
if (StringUtil.isBlank(ticket) || !StringUtil.equals(cacheTicket, ticket)) {
|
||||
throw new UserInvalidException(OAuth2TokenConstant.BEHAVIOR_NOT_CORRECT);
|
||||
}
|
||||
return super.user(request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.auth.granter;
|
||||
|
||||
import org.springblade.core.oauth2.constant.OAuth2TokenConstant;
|
||||
import org.springblade.core.oauth2.exception.UserInvalidException;
|
||||
import org.springblade.core.oauth2.granter.PasswordTokenGranter;
|
||||
import org.springblade.core.oauth2.handler.PasswordHandler;
|
||||
import org.springblade.core.oauth2.provider.OAuth2Request;
|
||||
import org.springblade.core.oauth2.service.OAuth2ClientService;
|
||||
import org.springblade.core.oauth2.service.OAuth2User;
|
||||
import org.springblade.core.oauth2.service.OAuth2UserService;
|
||||
import org.springblade.core.redis.cache.BladeRedis;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* CaptchaTokenGranter
|
||||
*
|
||||
* @author BladeX
|
||||
*/
|
||||
@Component
|
||||
public class CaptchaTokenGranter extends PasswordTokenGranter {
|
||||
|
||||
private final BladeRedis bladeRedis;
|
||||
|
||||
public CaptchaTokenGranter(OAuth2ClientService clientService, OAuth2UserService userService, PasswordHandler passwordHandler, BladeRedis bladeRedis) {
|
||||
super(clientService, userService, passwordHandler);
|
||||
this.bladeRedis = bladeRedis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return CAPTCHA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2User user(OAuth2Request request) {
|
||||
// 获取验证码信息
|
||||
String key = request.getCaptchaKey();
|
||||
String code = request.getCaptchaCode();
|
||||
// 获取验证码
|
||||
String redisCode = bladeRedis.getAndDel(OAuth2TokenConstant.CAPTCHA_CACHE_KEY + key);
|
||||
// 判断验证码
|
||||
if (code == null || !StringUtil.equalsIgnoreCase(redisCode, code)) {
|
||||
throw new UserInvalidException(OAuth2TokenConstant.CAPTCHA_NOT_CORRECT);
|
||||
}
|
||||
return super.user(request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.auth.granter;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springblade.core.launch.constant.TokenConstant;
|
||||
import org.springblade.core.oauth2.exception.UserInvalidException;
|
||||
import org.springblade.core.oauth2.granter.AbstractTokenGranter;
|
||||
import org.springblade.core.oauth2.handler.PasswordHandler;
|
||||
import org.springblade.core.oauth2.props.OAuth2Properties;
|
||||
import org.springblade.core.oauth2.provider.OAuth2Request;
|
||||
import org.springblade.core.oauth2.provider.OAuth2Token;
|
||||
import org.springblade.core.oauth2.service.OAuth2Client;
|
||||
import org.springblade.core.oauth2.service.OAuth2ClientService;
|
||||
import org.springblade.core.oauth2.service.OAuth2User;
|
||||
import org.springblade.core.oauth2.service.OAuth2UserService;
|
||||
import org.springblade.core.oauth2.service.impl.OAuth2UserDetail;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.core.tool.utils.NumberUtil;
|
||||
import org.springblade.core.tool.utils.SM2Util;
|
||||
import org.springblade.system.cache.ParamCache;
|
||||
import org.springblade.system.feign.IUserClient;
|
||||
import org.springblade.system.pojo.entity.User;
|
||||
import org.springblade.system.pojo.enums.UserType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static org.springblade.common.constant.ParamConstant.REGISTER_USER_VALUE;
|
||||
|
||||
/**
|
||||
* RegisterTokenGranter
|
||||
*
|
||||
* @author BladeX
|
||||
*/
|
||||
@Component
|
||||
public class RegisterTokenGranter extends AbstractTokenGranter {
|
||||
|
||||
private final IUserClient userClient;
|
||||
private final OAuth2Properties properties;
|
||||
|
||||
public RegisterTokenGranter(OAuth2ClientService clientService, OAuth2UserService userService, PasswordHandler passwordHandler, IUserClient userClient, OAuth2Properties properties) {
|
||||
super(clientService, userService, passwordHandler);
|
||||
this.userClient = userClient;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return REGISTER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2User user(OAuth2Request request) {
|
||||
// 校验注册功能是否开启
|
||||
Boolean registerOpen = Func.toBoolean(ParamCache.getValue(REGISTER_USER_VALUE), false);
|
||||
if (!registerOpen) {
|
||||
throw new UserInvalidException("注册功能暂未开启,请联系管理员");
|
||||
}
|
||||
|
||||
// 用户注册信息
|
||||
User user = new User();
|
||||
user.setUserType(UserType.of(request.getUserType()).getCategory());
|
||||
user.setTenantId(request.getTenantId());
|
||||
user.setAccount(request.getUsername());
|
||||
user.setPassword(SM2Util.decrypt(request.getPassword(), properties.getPublicKey(), properties.getPrivateKey()));
|
||||
user.setName(request.getName());
|
||||
user.setRealName(request.getName());
|
||||
user.setPhone(request.getPhone());
|
||||
user.setEmail(request.getEmail());
|
||||
|
||||
// 校验用户格式
|
||||
validateUser(user);
|
||||
|
||||
R<String> result = userClient.registerUser(user);
|
||||
|
||||
// 执行用户注册
|
||||
if (result.isSuccess()) {
|
||||
// 构建oauth2所需用户信息
|
||||
user.setId(NumberUtil.toLong(result.getData()));
|
||||
return convertOAuth2UserDetail(user, client(request));
|
||||
}
|
||||
throw new UserInvalidException(result.getMsg());
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2Token token(OAuth2User user, OAuth2Request request) {
|
||||
// 移除注册后返回的令牌与刷新令牌,防止外部攻击采用注册接口获取令牌并调用低权接口
|
||||
// 注意:
|
||||
// 1. 框架已默认开启严格模式,blade.secure.strict-token=true,不移除令牌则不受影响,注册令牌会被框架校验并拒绝
|
||||
// 2. 若自行关闭严格模式,blade.secure.strict-token=false,必须将令牌移除,否则注册获取令牌后可调用低权接口
|
||||
OAuth2Token token = super.token(user, request);
|
||||
token.getArgs().remove(TokenConstant.ACCESS_TOKEN);
|
||||
token.getArgs().remove(TokenConstant.REFRESH_TOKEN);
|
||||
return token;
|
||||
}
|
||||
|
||||
private void validateUser(User user) {
|
||||
Predicate<String> isNameValid = name -> name.matches("^([\\u4e00-\\u9fa5]{2,20}|[a-zA-Z]{2,10})$");
|
||||
Predicate<String> isUsernameValid = username -> username.matches("^(?=.*[a-zA-Z])[a-zA-Z0-9_\\-@]{3,20}$");
|
||||
Predicate<String> isPasswordValid = password -> password.matches("^(?=.*[0-9])(?=.*[a-zA-Z])[\\w@-]{6,20}$");
|
||||
Predicate<String> isPhoneValid = phone -> phone.matches("^1[3-9]\\d{9}$");
|
||||
Predicate<String> isEmailValid = email -> email.matches("^[A-Za-z0-9+_.-]+@(.+)$");
|
||||
if (!isNameValid.test(user.getName())) {
|
||||
throw new UserInvalidException("用户姓名长度必须在2-10之间,且仅能设置纯中文或纯英文");
|
||||
}
|
||||
if (!isUsernameValid.test(user.getAccount())) {
|
||||
throw new UserInvalidException("用户账号长度必须在3-20之间,且需要包含英文,可额外携带数字、下划线、横杠、@");
|
||||
}
|
||||
if (!isPasswordValid.test(user.getPassword())) {
|
||||
throw new UserInvalidException("用户密码长度必须在6-20之间,且需要包含英文与数字,可额外携带下划线、横杠、@");
|
||||
}
|
||||
if (!isPhoneValid.test(user.getPhone())) {
|
||||
throw new UserInvalidException("手机号格式不正确");
|
||||
}
|
||||
if (!isEmailValid.test(user.getEmail())) {
|
||||
throw new UserInvalidException("邮箱格式不正确");
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private OAuth2UserDetail convertOAuth2UserDetail(User user, OAuth2Client client) {
|
||||
OAuth2UserDetail userDetail = new OAuth2UserDetail();
|
||||
userDetail.setUserId(String.valueOf(user.getId()));
|
||||
userDetail.setTenantId(user.getTenantId());
|
||||
userDetail.setName(user.getName());
|
||||
userDetail.setRealName(user.getName());
|
||||
userDetail.setAccount(user.getAccount());
|
||||
userDetail.setPassword(user.getPassword());
|
||||
userDetail.setPhone(user.getPhone());
|
||||
userDetail.setEmail(user.getEmail());
|
||||
userDetail.setAuthorities(Collections.singletonList(REGISTER));
|
||||
userDetail.setClient(client);
|
||||
return userDetail;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.auth.granter;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springblade.core.oauth2.constant.OAuth2TokenConstant;
|
||||
import org.springblade.core.oauth2.exception.UserInvalidException;
|
||||
import org.springblade.core.oauth2.granter.AbstractTokenGranter;
|
||||
import org.springblade.core.oauth2.handler.PasswordHandler;
|
||||
import org.springblade.core.oauth2.props.OAuth2Properties;
|
||||
import org.springblade.core.oauth2.provider.OAuth2Request;
|
||||
import org.springblade.core.oauth2.service.OAuth2ClientService;
|
||||
import org.springblade.core.oauth2.service.OAuth2User;
|
||||
import org.springblade.core.oauth2.service.OAuth2UserService;
|
||||
import org.springblade.core.sms.model.SmsCode;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.core.tool.utils.SM2Util;
|
||||
import org.springblade.core.tool.utils.StringPool;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.core.tool.utils.WebUtil;
|
||||
import org.springblade.resource.feign.ISmsClient;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* SmsTokenGranter
|
||||
*
|
||||
* @author BladeX
|
||||
*/
|
||||
@Component
|
||||
public class SmsTokenGranter extends AbstractTokenGranter {
|
||||
|
||||
private final OAuth2UserService userService;
|
||||
private final ISmsClient smsClient;
|
||||
private final OAuth2Properties properties;
|
||||
|
||||
public SmsTokenGranter(OAuth2ClientService clientService, OAuth2UserService userService, PasswordHandler passwordHandler, ISmsClient smsClient, OAuth2Properties properties) {
|
||||
super(clientService, userService, passwordHandler);
|
||||
this.userService = userService;
|
||||
this.smsClient = smsClient;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return SMS_CODE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2User user(OAuth2Request request) {
|
||||
// 获取基础信息
|
||||
String tenantId = request.getTenantId();
|
||||
SmsCode smsCode = buildSmsCode();
|
||||
// 校验手机加密认证
|
||||
String decryptedPhone = SM2Util.decrypt(smsCode.getPhone(), properties.getPublicKey(), properties.getPrivateKey());
|
||||
if (StringUtil.isBlank(decryptedPhone)) {
|
||||
throw new UserInvalidException(OAuth2TokenConstant.USER_PHONE_NOT_FOUND);
|
||||
}
|
||||
// 获取短信验证信息
|
||||
R result = smsClient.validateMessage(tenantId, StringPool.EMPTY, smsCode.getId(), smsCode.getValue(), decryptedPhone);
|
||||
if (!result.isSuccess()) {
|
||||
throw new UserInvalidException(OAuth2TokenConstant.CAPTCHA_NOT_CORRECT);
|
||||
}
|
||||
// 获取用户信息
|
||||
OAuth2User user = userService.loadByPhone(decryptedPhone, request);
|
||||
// 校验用户信息
|
||||
if (!userService.validateUser(user)) {
|
||||
throw new UserInvalidException(OAuth2TokenConstant.TOKEN_NOT_CORRECT);
|
||||
}
|
||||
// 设置客户端信息
|
||||
user.setClient(client(request));
|
||||
return user;
|
||||
}
|
||||
|
||||
private SmsCode buildSmsCode() {
|
||||
HttpServletRequest request = WebUtil.getRequest();
|
||||
return new SmsCode().setId(request.getParameter("id"))
|
||||
.setPhone(request.getParameter("phone"))
|
||||
.setValue(request.getParameter("value"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.auth.granter;
|
||||
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.request.AuthRequest;
|
||||
import org.springblade.auth.utils.TokenUtil;
|
||||
import org.springblade.core.oauth2.exception.OAuth2ErrorCode;
|
||||
import org.springblade.core.oauth2.granter.AbstractTokenGranter;
|
||||
import org.springblade.core.oauth2.handler.PasswordHandler;
|
||||
import org.springblade.core.oauth2.provider.OAuth2Request;
|
||||
import org.springblade.core.oauth2.service.OAuth2ClientService;
|
||||
import org.springblade.core.oauth2.service.OAuth2User;
|
||||
import org.springblade.core.oauth2.service.OAuth2UserService;
|
||||
import org.springblade.core.oauth2.utils.OAuth2ExceptionUtil;
|
||||
import org.springblade.core.social.props.SocialProperties;
|
||||
import org.springblade.core.social.utils.SocialUtil;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.core.tool.utils.BeanUtil;
|
||||
import org.springblade.system.pojo.entity.UserInfo;
|
||||
import org.springblade.system.pojo.entity.UserOauth;
|
||||
import org.springblade.system.feign.IUserClient;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* SocialTokenGranter
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Component
|
||||
public class SocialTokenGranter extends AbstractTokenGranter {
|
||||
|
||||
|
||||
private static final Integer AUTH_SUCCESS_CODE = 2000;
|
||||
|
||||
private final IUserClient userClient;
|
||||
private final SocialProperties socialProperties;
|
||||
|
||||
|
||||
public SocialTokenGranter(OAuth2ClientService clientService, OAuth2UserService oAuth2UserService, PasswordHandler passwordHandler, IUserClient userClient, SocialProperties socialProperties) {
|
||||
super(clientService, oAuth2UserService, passwordHandler);
|
||||
this.userClient = userClient;
|
||||
this.socialProperties = socialProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return SOCIAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2User user(OAuth2Request request) {
|
||||
String tenantId = request.getTenantId();
|
||||
// 开放平台来源
|
||||
String sourceParameter = request.getSource();
|
||||
// 匹配是否有别名定义
|
||||
String source = socialProperties.getAlias().getOrDefault(sourceParameter, sourceParameter);
|
||||
// 开放平台授权码
|
||||
String code = request.getCode();
|
||||
// 开放平台状态吗
|
||||
String state = request.getState();
|
||||
|
||||
// 获取开放平台授权数据
|
||||
AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
|
||||
AuthCallback authCallback = new AuthCallback();
|
||||
authCallback.setCode(code);
|
||||
authCallback.setState(state);
|
||||
AuthResponse<?> authResponse = authRequest.login(authCallback);
|
||||
AuthUser authUser = null;
|
||||
if (authResponse.getCode() == AUTH_SUCCESS_CODE) {
|
||||
authUser = (AuthUser) authResponse.getData();
|
||||
} else {
|
||||
OAuth2ExceptionUtil.throwFromCode(OAuth2ErrorCode.INVALID_USER);
|
||||
}
|
||||
|
||||
// 组装数据
|
||||
UserOauth userOauth = Objects.requireNonNull(BeanUtil.copyProperties(authUser, UserOauth.class));
|
||||
userOauth.setSource(authUser.getSource());
|
||||
userOauth.setTenantId(tenantId);
|
||||
userOauth.setUuid(authUser.getUuid());
|
||||
R<UserInfo> result = userClient.userAuthInfo(userOauth);
|
||||
if (!result.isSuccess()) {
|
||||
OAuth2ExceptionUtil.throwFromCode(OAuth2ErrorCode.INVALID_USER);
|
||||
}
|
||||
|
||||
// 设置Oauth2用户信息
|
||||
OAuth2User user = TokenUtil.convertUser(result.getData(), request);
|
||||
// 设置客户端信息
|
||||
user.setClient(client(request));
|
||||
return user;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.auth.handler;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.common.constant.TenantConstant;
|
||||
import org.springblade.core.launch.props.BladeProperties;
|
||||
import org.springblade.core.oauth2.exception.ExceptionCode;
|
||||
import org.springblade.core.oauth2.handler.AbstractAuthorizationHandler;
|
||||
import org.springblade.core.oauth2.props.OAuth2Properties;
|
||||
import org.springblade.core.oauth2.provider.OAuth2Request;
|
||||
import org.springblade.core.oauth2.provider.OAuth2Validation;
|
||||
import org.springblade.core.oauth2.service.OAuth2User;
|
||||
import org.springblade.core.tenant.BladeTenantProperties;
|
||||
import org.springblade.core.tool.jackson.JsonUtil;
|
||||
import org.springblade.core.tool.utils.DateUtil;
|
||||
import org.springblade.core.tool.utils.DesUtil;
|
||||
import org.springblade.core.tool.utils.SM2Util;
|
||||
import org.springblade.system.cache.SysCache;
|
||||
import org.springblade.system.pojo.entity.Tenant;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* BladeAuthorizationHandler
|
||||
*
|
||||
* @author BladeX
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class BladeAuthorizationHandler extends AbstractAuthorizationHandler {
|
||||
|
||||
private final BladeProperties bladeProperties;
|
||||
private final BladeTenantProperties tenantProperties;
|
||||
private final OAuth2Properties oAuth2Properties;
|
||||
private final BladeLockHandler lockHandler;
|
||||
private final BladeLogHandler logHandler;
|
||||
|
||||
/**
|
||||
* 自定义弱密码列表
|
||||
*/
|
||||
private static final List<String> WEAK_PASSWORDS = List.of("admin", "hr", "manager", "boss");
|
||||
|
||||
/**
|
||||
* 认证前校验
|
||||
*
|
||||
* @param request 请求信息
|
||||
* @return boolean
|
||||
*/
|
||||
@Override
|
||||
public OAuth2Validation preValidation(OAuth2Request request) {
|
||||
if (request.isPassword() || request.isCaptchaCode()) {
|
||||
// 生产环境弱密码校验
|
||||
if (bladeProperties.isProd() && isWeakPassword(request.getPassword())) {
|
||||
return buildValidationFailure(ExceptionCode.INVALID_USER_PASSWORD);
|
||||
}
|
||||
// 判断账号是否锁定
|
||||
OAuth2Validation accountValidation = lockHandler.validateAccountLock(request.getTenantId(), request.getUsername());
|
||||
if (!accountValidation.isSuccess()) {
|
||||
return accountValidation;
|
||||
}
|
||||
// 判断IP是否锁定
|
||||
OAuth2Validation ipValidation = lockHandler.validateIpLock(request.getTenantId());
|
||||
if (!ipValidation.isSuccess()) {
|
||||
return ipValidation;
|
||||
}
|
||||
}
|
||||
return super.preValidation(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 认证前失败回调
|
||||
*
|
||||
* @param validation 失败信息
|
||||
*/
|
||||
@Override
|
||||
public void preFailure(OAuth2Request request, OAuth2Validation validation) {
|
||||
// 处理认证失败,增加错误次数
|
||||
lockHandler.handleAuthFailure(request.getTenantId(), request.getUsername());
|
||||
|
||||
log.error("用户:{},认证失败,失败原因:{}", request.getUsername(), validation.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 认证校验
|
||||
*
|
||||
* @param user 用户信息
|
||||
* @param request 请求信息
|
||||
* @return boolean
|
||||
*/
|
||||
@Override
|
||||
public OAuth2Validation authValidation(OAuth2User user, OAuth2Request request) {
|
||||
// 密码模式、刷新token模式、验证码模式需要校验租户状态
|
||||
if (request.isPassword() || request.isRefreshToken() || request.isCaptchaCode()) {
|
||||
// 租户校验
|
||||
OAuth2Validation tenantValidation = validateTenant(user.getTenantId());
|
||||
if (!tenantValidation.isSuccess()) {
|
||||
return tenantValidation;
|
||||
}
|
||||
}
|
||||
return super.authValidation(user, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 认证成功回调
|
||||
*
|
||||
* @param user 用户信息
|
||||
*/
|
||||
@Override
|
||||
public void authSuccessful(OAuth2User user, OAuth2Request request) {
|
||||
// 处理认证成功,清空错误次数
|
||||
lockHandler.handleAuthSuccess(user.getTenantId(), user.getAccount());
|
||||
// 记录认证成功日志
|
||||
logHandler.handleAuthLog(user, request);
|
||||
|
||||
log.info("用户:{},认证成功", user.getAccount());
|
||||
}
|
||||
|
||||
/**
|
||||
* 认证失败回调
|
||||
*
|
||||
* @param user 用户信息
|
||||
* @param validation 失败信息
|
||||
*/
|
||||
@Override
|
||||
public void authFailure(OAuth2User user, OAuth2Request request, OAuth2Validation validation) {
|
||||
// 自定义认证失败回调
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为弱密码
|
||||
*
|
||||
* @param rawPassword 加密密码
|
||||
* @return boolean
|
||||
*/
|
||||
private boolean isWeakPassword(String rawPassword) {
|
||||
// 获取公钥
|
||||
String publicKey = oAuth2Properties.getPublicKey();
|
||||
// 获取私钥
|
||||
String privateKey = oAuth2Properties.getPrivateKey();
|
||||
// 解密密码
|
||||
String decryptPassword = SM2Util.decrypt(rawPassword, publicKey, privateKey);
|
||||
return WEAK_PASSWORDS.stream()
|
||||
.anyMatch(weakPass -> weakPass.equalsIgnoreCase(decryptPassword));
|
||||
}
|
||||
|
||||
/**
|
||||
* 租户授权校验
|
||||
*
|
||||
* @param tenantId 租户id
|
||||
* @return OAuth2Validation
|
||||
*/
|
||||
private OAuth2Validation validateTenant(String tenantId) {
|
||||
// 租户校验
|
||||
Tenant tenant = SysCache.getTenant(tenantId);
|
||||
if (tenant == null) {
|
||||
return buildValidationFailure(ExceptionCode.USER_TENANT_NOT_FOUND);
|
||||
}
|
||||
// 租户授权时间校验
|
||||
Date expireTime = tenant.getExpireTime();
|
||||
if (tenantProperties.getLicense()) {
|
||||
String licenseKey = tenant.getLicenseKey();
|
||||
String decrypt = DesUtil.decryptFormHex(licenseKey, TenantConstant.DES_KEY);
|
||||
Tenant license = JsonUtil.parse(decrypt, Tenant.class);
|
||||
if (license == null || !license.getId().equals(tenant.getId())) {
|
||||
return buildValidationFailure(ExceptionCode.UNAUTHORIZED_USER_TENANT);
|
||||
}
|
||||
expireTime = license.getExpireTime();
|
||||
}
|
||||
if (expireTime != null && expireTime.before(DateUtil.now())) {
|
||||
return buildValidationFailure(ExceptionCode.UNAUTHORIZED_USER_TENANT);
|
||||
}
|
||||
return new OAuth2Validation();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.auth.handler;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.oauth2.exception.ExceptionCode;
|
||||
import org.springblade.core.oauth2.provider.OAuth2Validation;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.core.tool.utils.WebUtil;
|
||||
import org.springblade.system.feign.IAuthLockClient;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
|
||||
/**
|
||||
* 失败锁定处理器
|
||||
* 统一管理账号锁定和IP锁定逻辑
|
||||
*
|
||||
* @author BladeX
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class BladeLockHandler {
|
||||
|
||||
private final IAuthLockClient authLockClient;
|
||||
|
||||
/**
|
||||
* 校验账号是否锁定
|
||||
*
|
||||
* @param tenantId 租户id
|
||||
* @param account 账号
|
||||
* @return OAuth2Validation
|
||||
*/
|
||||
public OAuth2Validation validateAccountLock(String tenantId, String account) {
|
||||
try {
|
||||
R<Boolean> result = authLockClient.isAccountLocked(tenantId, account);
|
||||
if (result.isSuccess() && Boolean.TRUE.equals(result.getData())) {
|
||||
log.error("用户:{},已锁定,请求ip:{}", account, WebUtil.getIP());
|
||||
return buildValidationFailure();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("账号锁定校验异常: {}", e.getMessage());
|
||||
}
|
||||
return new OAuth2Validation();
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验IP是否锁定
|
||||
*
|
||||
* @param tenantId 租户id
|
||||
* @return OAuth2Validation
|
||||
*/
|
||||
public OAuth2Validation validateIpLock(String tenantId) {
|
||||
String clientIp = WebUtil.getIP();
|
||||
try {
|
||||
R<Boolean> result = authLockClient.isIpLocked(tenantId, clientIp);
|
||||
if (result.isSuccess() && Boolean.TRUE.equals(result.getData())) {
|
||||
log.error("IP:{},已锁定", clientIp);
|
||||
return buildValidationFailure();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("IP锁定校验异常: {}", e.getMessage());
|
||||
}
|
||||
return new OAuth2Validation();
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理认证失败
|
||||
* 同时增加账号和IP错误次数
|
||||
*
|
||||
* @param tenantId 租户id
|
||||
* @param account 账号
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
public void handleAuthFailure(String tenantId, String account, Long userId) {
|
||||
String ip = WebUtil.getIP();
|
||||
String userAgent = WebUtil.getUserAgent();
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
authLockClient.addAccountFailCount(tenantId, account, userId, ip, userAgent);
|
||||
authLockClient.addIpFailCount(tenantId, ip, userAgent);
|
||||
} catch (Exception e) {
|
||||
log.warn("认证失败计数异常: {}", e.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理认证失败
|
||||
* 同时增加账号和IP错误次数
|
||||
*
|
||||
* @param tenantId 租户id
|
||||
* @param account 账号
|
||||
*/
|
||||
public void handleAuthFailure(String tenantId, String account) {
|
||||
handleAuthFailure(tenantId, account, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理认证成功
|
||||
* 释放系统自动锁定
|
||||
*
|
||||
* @param tenantId 租户id
|
||||
* @param account 账号
|
||||
*/
|
||||
public void handleAuthSuccess(String tenantId, String account) {
|
||||
String ip = WebUtil.getIP();
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
authLockClient.releaseSystemLock(tenantId, account);
|
||||
authLockClient.releaseSystemIpLock(tenantId, ip);
|
||||
} catch (Exception e) {
|
||||
log.warn("认证成功释放锁定异常: {}", e.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建校验失败结果
|
||||
*
|
||||
* @return OAuth2Validation
|
||||
*/
|
||||
private OAuth2Validation buildValidationFailure() {
|
||||
OAuth2Validation validation = new OAuth2Validation();
|
||||
validation.setSuccess(false);
|
||||
validation.setCode(ExceptionCode.USER_TOO_MANY_FAILS.getCode());
|
||||
validation.setMessage(ExceptionCode.USER_TOO_MANY_FAILS.getMessage());
|
||||
return validation;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.auth.handler;
|
||||
|
||||
import org.springblade.core.launch.props.BladeProperties;
|
||||
import org.springblade.core.launch.server.ServerInfo;
|
||||
import org.springblade.core.oauth2.provider.OAuth2Request;
|
||||
import org.springblade.core.oauth2.service.OAuth2User;
|
||||
import org.springblade.core.tool.utils.DateUtil;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.core.tool.utils.WebUtil;
|
||||
import org.springblade.system.pojo.entity.AuthLog;
|
||||
import org.springblade.system.feign.IAuthLogClient;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* 认证日志处理器
|
||||
* 在用户认证成功时异步记录登录日志
|
||||
*
|
||||
* @author BladeX
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class BladeLogHandler {
|
||||
|
||||
private final IAuthLogClient authLogClient;
|
||||
private final BladeProperties bladeProperties;
|
||||
private final ServerInfo serverInfo;
|
||||
|
||||
/**
|
||||
* 记录认证成功日志
|
||||
*
|
||||
* @param user 用户信息
|
||||
* @param request 请求信息
|
||||
*/
|
||||
public void handleAuthLog(OAuth2User user, OAuth2Request request) {
|
||||
// 异步记录日志,避免影响认证性能
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
AuthLog authLog = buildAuthLog(user, request);
|
||||
authLogClient.saveAuthLog(authLog);
|
||||
} catch (Exception exception) {
|
||||
log.error("记录认证日志异常:{}", exception.getMessage(), exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建认证日志实体
|
||||
*
|
||||
* @param user 用户信息
|
||||
* @param request 请求信息
|
||||
* @return AuthLog
|
||||
*/
|
||||
private AuthLog buildAuthLog(OAuth2User user, OAuth2Request request) {
|
||||
AuthLog authLog = new AuthLog();
|
||||
authLog.setUserId(Func.toLong(user.getUserId()));
|
||||
authLog.setTenantId(user.getTenantId());
|
||||
authLog.setServiceId(bladeProperties.getName());
|
||||
authLog.setServerIp(serverInfo.getIpWithPort());
|
||||
authLog.setServerHost(serverInfo.getHostName());
|
||||
authLog.setEnv(bladeProperties.getEnv());
|
||||
authLog.setAccount(user.getAccount());
|
||||
authLog.setRealName(user.getRealName());
|
||||
authLog.setGrantType(request.getGrantType());
|
||||
authLog.setRemoteIp(WebUtil.getIP(request.getHttpRequest()));
|
||||
authLog.setUserAgent(WebUtil.getUserAgent(request.getHttpRequest()));
|
||||
authLog.setLoginTime(DateUtil.now());
|
||||
return authLog;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.auth.handler;
|
||||
|
||||
import org.springblade.core.oauth2.handler.OAuth2PasswordHandler;
|
||||
import org.springblade.core.oauth2.props.OAuth2Properties;
|
||||
|
||||
/**
|
||||
* BladePasswordHandler
|
||||
*
|
||||
* @author BladeX
|
||||
*/
|
||||
public class BladePasswordHandler extends OAuth2PasswordHandler {
|
||||
|
||||
public BladePasswordHandler(OAuth2Properties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断密码是否匹配
|
||||
*
|
||||
* @param rawPassword 请求时提交的原密码
|
||||
* @param encodedPassword 数据库加密后的密码
|
||||
* @return boolean
|
||||
*/
|
||||
@Override
|
||||
public boolean matches(String rawPassword, String encodedPassword) {
|
||||
return super.matches(rawPassword, encodedPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密密码规则
|
||||
*
|
||||
* @param rawPassword 密码
|
||||
* @return 加密后的密码
|
||||
*/
|
||||
@Override
|
||||
public String encode(String rawPassword) {
|
||||
return super.encode(rawPassword);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.auth.handler;
|
||||
|
||||
import org.springblade.core.jwt.props.JwtProperties;
|
||||
import org.springblade.core.launch.constant.TokenConstant;
|
||||
import org.springblade.core.oauth2.handler.OAuth2TokenHandler;
|
||||
import org.springblade.core.oauth2.provider.OAuth2Request;
|
||||
import org.springblade.core.oauth2.provider.OAuth2Token;
|
||||
import org.springblade.core.oauth2.service.OAuth2User;
|
||||
import org.springblade.core.tool.support.Kv;
|
||||
|
||||
/**
|
||||
* BladeTokenHandler
|
||||
*
|
||||
* @author BladeX
|
||||
*/
|
||||
public class BladeTokenHandler extends OAuth2TokenHandler {
|
||||
|
||||
public BladeTokenHandler(JwtProperties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2Token enhance(OAuth2User user, OAuth2Token token, OAuth2Request request) {
|
||||
// 父类令牌状态配置
|
||||
OAuth2Token enhanceToken = super.enhance(user, token, request);
|
||||
|
||||
// 令牌统一处理,增加或删减字段
|
||||
Kv args = enhanceToken.getArgs();
|
||||
args.set(TokenConstant.USER_NAME, user.getAccount());
|
||||
|
||||
// 返回令牌
|
||||
return enhanceToken;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.auth.service;
|
||||
|
||||
import org.springblade.core.oauth2.provider.OAuth2Request;
|
||||
import org.springblade.core.oauth2.service.OAuth2Client;
|
||||
import org.springblade.core.oauth2.service.impl.OAuth2ClientDetailService;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
/**
|
||||
* BladeClientDetailService
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public class BladeClientDetailService extends OAuth2ClientDetailService {
|
||||
public BladeClientDetailService(JdbcTemplate jdbcTemplate) {
|
||||
super(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2Client loadByClientId(String clientId) {
|
||||
return super.loadByClientId(clientId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2Client loadByClientId(String clientId, OAuth2Request request) {
|
||||
return super.loadByClientId(clientId, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateClient(OAuth2Client client, String clientId, String clientSecret) {
|
||||
return super.validateClient(client, clientId, clientSecret);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateGranter(OAuth2Client client, String grantType) {
|
||||
return super.validateGranter(client, grantType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.auth.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springblade.auth.utils.TokenUtil;
|
||||
import org.springblade.core.oauth2.exception.OAuth2ErrorCode;
|
||||
import org.springblade.core.oauth2.provider.OAuth2Request;
|
||||
import org.springblade.core.oauth2.service.OAuth2User;
|
||||
import org.springblade.core.oauth2.service.OAuth2UserService;
|
||||
import org.springblade.core.oauth2.utils.OAuth2ExceptionUtil;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.system.feign.IUserClient;
|
||||
import org.springblade.system.pojo.entity.UserInfo;
|
||||
import org.springblade.system.pojo.enums.UserType;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* BladeUserDetailService
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class BladeUserDetailService implements OAuth2UserService {
|
||||
private final IUserClient userClient;
|
||||
|
||||
@Override
|
||||
public OAuth2User loadByUserId(String userId, OAuth2Request request) {
|
||||
// 获取用户参数
|
||||
String userType = Optional.ofNullable(request.getUserType())
|
||||
.filter(s -> !StringUtil.isBlank(s))
|
||||
.orElse(UserType.WEB.getName());
|
||||
|
||||
// 获取用户信息
|
||||
R<UserInfo> result = userClient.userInfo(Func.toLong(userId), userType);
|
||||
if (!result.isSuccess()) {
|
||||
OAuth2ExceptionUtil.throwFromCode(OAuth2ErrorCode.INVALID_USER);
|
||||
}
|
||||
// 构建oauth2用户信息
|
||||
return TokenUtil.convertUser(result.getData(), request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2User loadByUsername(String username, OAuth2Request request) {
|
||||
// 获取用户参数
|
||||
String userType = Optional.ofNullable(request.getUserType())
|
||||
.filter(s -> !StringUtil.isBlank(s))
|
||||
.orElse(UserType.WEB.getName());
|
||||
String tenantId = request.getTenantId();
|
||||
|
||||
// 获取用户信息
|
||||
R<UserInfo> result = userClient.userInfo(tenantId, username, userType);
|
||||
if (!result.isSuccess()) {
|
||||
return null;
|
||||
}
|
||||
// 构建oauth2用户信息
|
||||
return TokenUtil.convertUser(result.getData(), request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2User loadByPhone(String phone, OAuth2Request request) {
|
||||
// 获取用户参数
|
||||
String userType = Optional.ofNullable(request.getUserType())
|
||||
.filter(s -> !StringUtil.isBlank(s))
|
||||
.orElse(UserType.WEB.getName());
|
||||
String tenantId = request.getTenantId();
|
||||
|
||||
// 获取用户信息
|
||||
R<UserInfo> result = userClient.userInfoByPhone(tenantId, phone, userType);
|
||||
if (!result.isSuccess()) {
|
||||
return null;
|
||||
}
|
||||
// 构建oauth2用户信息
|
||||
return TokenUtil.convertUser(result.getData(), request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateUser(OAuth2User user) {
|
||||
return Optional.ofNullable(user)
|
||||
.filter(u -> u.getUserId() != null && !u.getUserId().isEmpty()) // 检查userId不为空
|
||||
.filter(u -> u.getAuthorities() != null && !u.getAuthorities().isEmpty()) // 检查authorities不为空
|
||||
.isPresent(); // 如果上述条件都满足,则返回true,否则返回false
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.auth.utils;
|
||||
|
||||
import org.springblade.core.oauth2.provider.OAuth2Request;
|
||||
import org.springblade.core.oauth2.service.OAuth2User;
|
||||
import org.springblade.core.oauth2.service.impl.OAuth2UserDetail;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.system.cache.SysCache;
|
||||
import org.springblade.system.pojo.entity.User;
|
||||
import org.springblade.system.pojo.entity.UserInfo;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* 认证工具类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public class TokenUtil {
|
||||
|
||||
/**
|
||||
* 系统用户转换为OAuth2标准用户
|
||||
*
|
||||
* @param userInfo 用户信息
|
||||
* @param request 请求信息
|
||||
* @return OAuth2User
|
||||
*/
|
||||
public static OAuth2User convertUser(UserInfo userInfo, OAuth2Request request) {
|
||||
// 为空则返回null
|
||||
if (userInfo == null || userInfo.getUser() == null) {
|
||||
return null;
|
||||
}
|
||||
User user = userInfo.getUser();
|
||||
String userDept = request.getUserDept();
|
||||
String userRole = request.getUserRole();
|
||||
// 单独指定部门
|
||||
if (Func.isNotEmpty(userDept) && user.getDeptId().contains(userDept)) {
|
||||
user.setDeptId(userDept);
|
||||
}
|
||||
// 单独指定角色
|
||||
if (Func.isNotEmpty(userRole) && user.getRoleId().contains(userRole)) {
|
||||
user.setRoleId(userRole);
|
||||
userInfo.setRoles(SysCache.getRoleAliases(userRole));
|
||||
}
|
||||
// 构建oauth2所需用户信息
|
||||
OAuth2UserDetail userDetail = new OAuth2UserDetail();
|
||||
userDetail.setUserId(String.valueOf(user.getId()));
|
||||
userDetail.setOauthId(userInfo.getOauthId());
|
||||
userDetail.setTenantId(user.getTenantId());
|
||||
userDetail.setName(user.getName());
|
||||
userDetail.setRealName(user.getRealName());
|
||||
userDetail.setAccount(user.getAccount());
|
||||
userDetail.setPassword(user.getPassword());
|
||||
userDetail.setDeptId(user.getDeptId());
|
||||
userDetail.setPostId(user.getPostId());
|
||||
userDetail.setRoleId(user.getRoleId());
|
||||
userDetail.setRoleName(Func.join(userInfo.getRoles()));
|
||||
userDetail.setAvatar(user.getAvatar());
|
||||
userDetail.setAuthorities(userInfo.getRoles());
|
||||
userDetail.setDetail(userInfo.getDetail());
|
||||
return userDetail;
|
||||
}
|
||||
|
||||
}
|
||||
15
blade-auth/src/main/resources/application-dev.yml
Normal file
15
blade-auth/src/main/resources/application-dev.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
#服务器端口
|
||||
server:
|
||||
port: 8100
|
||||
|
||||
#数据源配置
|
||||
spring:
|
||||
datasource:
|
||||
url: ${blade.datasource.dev.url}
|
||||
username: ${blade.datasource.dev.username}
|
||||
password: ${blade.datasource.dev.password}
|
||||
|
||||
#第三方登陆
|
||||
social:
|
||||
enabled: true
|
||||
domain: http://127.0.0.1:2888
|
||||
15
blade-auth/src/main/resources/application-prod.yml
Normal file
15
blade-auth/src/main/resources/application-prod.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
#服务器端口
|
||||
server:
|
||||
port: 8100
|
||||
|
||||
#数据源配置
|
||||
spring:
|
||||
datasource:
|
||||
url: ${blade.datasource.prod.url}
|
||||
username: ${blade.datasource.prod.username}
|
||||
password: ${blade.datasource.prod.password}
|
||||
|
||||
#第三方登陆
|
||||
social:
|
||||
enabled: true
|
||||
domain: http://127.0.0.1:2888
|
||||
15
blade-auth/src/main/resources/application-test.yml
Normal file
15
blade-auth/src/main/resources/application-test.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
#服务器端口
|
||||
server:
|
||||
port: 8100
|
||||
|
||||
#数据源配置
|
||||
spring:
|
||||
datasource:
|
||||
url: ${blade.datasource.test.url}
|
||||
username: ${blade.datasource.test.username}
|
||||
password: ${blade.datasource.test.password}
|
||||
|
||||
#第三方登陆
|
||||
social:
|
||||
enabled: true
|
||||
domain: http://127.0.0.1:2888
|
||||
65
blade-auth/src/main/resources/application.yml
Normal file
65
blade-auth/src/main/resources/application.yml
Normal file
@@ -0,0 +1,65 @@
|
||||
# 在使用Spring默认数据源Hikari的情况下配置以下配置项
|
||||
spring:
|
||||
datasource:
|
||||
hikari:
|
||||
# 自动提交从池中返回的连接
|
||||
auto-commit: true
|
||||
# 连接池中维护的最小空闲连接数
|
||||
minimum-idle: 10
|
||||
# 连接池中允许的最大连接数。缺省值:10;推荐的公式:((core_count * 2) + effective_spindle_count)
|
||||
maximum-pool-size: 60
|
||||
# 空闲连接超时时间,默认值600000(10分钟),大于等于max-lifetime且max-lifetime>0,会被重置为0;不等于0且小于10秒,会被重置为10秒。
|
||||
# 只有空闲连接数大于最大连接数且空闲时间超过该值,才会被释放
|
||||
idle-timeout: 30000
|
||||
# 连接最大存活时间.不等于0且小于30秒,会被重置为默认值30分钟.设置应该比mysql设置的超时时间短
|
||||
max-lifetime: 1800000
|
||||
# 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 缺省:30秒
|
||||
connection-timeout: 30000
|
||||
# 连接测试查询
|
||||
connection-test-query: select 1
|
||||
#connection-test-query: select 1 from dual
|
||||
freemarker:
|
||||
# 模板后缀名
|
||||
suffix: .ftl
|
||||
# 文档类型
|
||||
content-type: text/html
|
||||
# 页面编码
|
||||
charset: UTF-8
|
||||
# 页面缓存
|
||||
cache: false
|
||||
# 模板路径
|
||||
template-loader-path: classpath:/templates/
|
||||
web:
|
||||
# 资源路径
|
||||
resources:
|
||||
static-locations: classpath:/static/
|
||||
|
||||
#swagger文档
|
||||
swagger:
|
||||
base-packages:
|
||||
- org.springblade
|
||||
- org.springframework.security.oauth2.provider.endpoint
|
||||
|
||||
#第三方登陆
|
||||
social:
|
||||
oauth:
|
||||
GITHUB:
|
||||
client-id: 233************
|
||||
client-secret: 233************************************
|
||||
redirect-uri: ${social.domain}/oauth/redirect/github
|
||||
GITEE:
|
||||
client-id: 233************
|
||||
client-secret: 233************************************
|
||||
redirect-uri: ${social.domain}/oauth/redirect/gitee
|
||||
WECHAT_OPEN:
|
||||
client-id: 233************
|
||||
client-secret: 233************************************
|
||||
redirect-uri: ${social.domain}/oauth/redirect/wechat
|
||||
QQ:
|
||||
client-id: 233************
|
||||
client-secret: 233************************************
|
||||
redirect-uri: ${social.domain}/oauth/redirect/qq
|
||||
DINGTALK:
|
||||
client-id: 233************
|
||||
client-secret: 233************************************
|
||||
redirect-uri: ${social.domain}/oauth/redirect/dingtalk
|
||||
Reference in New Issue
Block a user