mirror of https://gitee.com/stylefeng/roses
【auth】更新auth模块的登录流程,抽象两个密码相关的接口
parent
1754c21bc8
commit
a5fc70e51b
|
@ -0,0 +1,31 @@
|
|||
package cn.stylefeng.roses.kernel.auth.api.password;
|
||||
|
||||
/**
|
||||
* 密码存储时,将密码进行加密的api
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/21 16:50
|
||||
*/
|
||||
public interface PasswordStoredEncryptApi {
|
||||
|
||||
/**
|
||||
* 加密密码
|
||||
*
|
||||
* @param originPassword 密码明文,待加密的密码
|
||||
* @return 加密后的密码密文
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/21 16:52
|
||||
*/
|
||||
String encrypt(String originPassword);
|
||||
|
||||
/**
|
||||
* 校验密码加密前和加密后是否一致,多用于判断用户输入密码是否正确
|
||||
*
|
||||
* @param encryptBefore 密码明文
|
||||
* @return true-密码正确,false-密码错误
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/21 17:09
|
||||
*/
|
||||
Boolean checkPassword(String encryptBefore, String encryptAfter);
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package cn.stylefeng.roses.kernel.auth.api.password;
|
||||
|
||||
/**
|
||||
* 密码传输时,将密码进行加密和解密的api
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/21 16:50
|
||||
*/
|
||||
public interface PasswordTransferEncryptApi {
|
||||
|
||||
/**
|
||||
* 加密密码
|
||||
*
|
||||
* @param originPassword 密码明文,待加密的密码
|
||||
* @return 加密后的密码密文
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/21 16:52
|
||||
*/
|
||||
String encrypt(String originPassword);
|
||||
|
||||
/**
|
||||
* 解密密码信息
|
||||
*
|
||||
* @param encryptedPassword 加密的密码
|
||||
* @return 解密后的密码明文
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/21 16:51
|
||||
*/
|
||||
String decrypt(String encryptedPassword);
|
||||
|
||||
}
|
|
@ -1,14 +1,14 @@
|
|||
package cn.stylefeng.roses.kernel.auth.auth;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.digest.BCrypt;
|
||||
import cn.stylefeng.roses.kernel.auth.api.AuthServiceApi;
|
||||
import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi;
|
||||
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
|
||||
import cn.stylefeng.roses.kernel.auth.api.exception.AuthException;
|
||||
import cn.stylefeng.roses.kernel.auth.api.exception.enums.AuthExceptionEnum;
|
||||
import cn.stylefeng.roses.kernel.auth.api.expander.AuthConfigExpander;
|
||||
import cn.stylefeng.roses.kernel.auth.api.password.PasswordStoredEncryptApi;
|
||||
import cn.stylefeng.roses.kernel.auth.api.password.PasswordTransferEncryptApi;
|
||||
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginRequest;
|
||||
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginResponse;
|
||||
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
|
||||
|
@ -16,7 +16,6 @@ import cn.stylefeng.roses.kernel.jwt.api.context.JwtContext;
|
|||
import cn.stylefeng.roses.kernel.jwt.api.exception.JwtException;
|
||||
import cn.stylefeng.roses.kernel.jwt.api.pojo.payload.DefaultJwtPayload;
|
||||
import cn.stylefeng.roses.kernel.rule.util.HttpServletUtil;
|
||||
import cn.stylefeng.roses.kernel.system.ResourceServiceApi;
|
||||
import cn.stylefeng.roses.kernel.system.UserServiceApi;
|
||||
import cn.stylefeng.roses.kernel.system.enums.UserStatusEnum;
|
||||
import cn.stylefeng.roses.kernel.system.pojo.user.UserLoginInfoDTO;
|
||||
|
@ -46,7 +45,10 @@ public class AuthServiceImpl implements AuthServiceApi {
|
|||
private SessionManagerApi sessionManagerApi;
|
||||
|
||||
@Resource
|
||||
private ResourceServiceApi resourceServiceApi;
|
||||
private PasswordStoredEncryptApi passwordStoredEncryptApi;
|
||||
|
||||
@Resource
|
||||
private PasswordTransferEncryptApi passwordTransferEncryptApi;
|
||||
|
||||
@Override
|
||||
public LoginResponse login(LoginRequest loginRequest) {
|
||||
|
@ -138,46 +140,49 @@ public class AuthServiceImpl implements AuthServiceApi {
|
|||
}
|
||||
}
|
||||
|
||||
// 2.获取用户密码的加密值和用户的状态
|
||||
// 2. 解密密码的密文
|
||||
String decryptPassword = passwordTransferEncryptApi.decrypt(loginRequest.getPassword());
|
||||
|
||||
// 3. 获取用户密码的加密值和用户的状态
|
||||
UserLoginInfoDTO userValidateInfo = userServiceApi.getUserLoginInfo(loginRequest.getAccount());
|
||||
|
||||
// 3.校验用户密码是否正确(BCrypt算法)
|
||||
// 4. 校验用户密码是否正确(BCrypt算法)
|
||||
if (validatePassword) {
|
||||
if (ObjectUtil.isEmpty(userValidateInfo.getUserPasswordHexed()) || !BCrypt.checkpw(loginRequest.getPassword(), userValidateInfo.getUserPasswordHexed())) {
|
||||
Boolean checkResult = passwordStoredEncryptApi.checkPassword(decryptPassword, userValidateInfo.getUserPasswordHexed());
|
||||
if (!checkResult) {
|
||||
throw new AuthException(AuthExceptionEnum.USERNAME_PASSWORD_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
// 4.校验用户是否异常(不是正常状态)
|
||||
// 5. 校验用户是否异常(不是正常状态)
|
||||
if (!UserStatusEnum.ENABLE.getCode().equals(userValidateInfo.getUserStatus())) {
|
||||
String userTip = StrUtil.format(AuthExceptionEnum.USER_STATUS_ERROR.getErrorCode(), UserStatusEnum.getCodeMessage(userValidateInfo.getUserStatus()));
|
||||
throw new AuthException(AuthExceptionEnum.USER_STATUS_ERROR.getErrorCode(), userTip);
|
||||
}
|
||||
|
||||
// 5.获取LoginUser,用于用户的缓存
|
||||
// 6. 获取LoginUser,用于用户的缓存
|
||||
LoginUser loginUser = userValidateInfo.getLoginUser();
|
||||
|
||||
// 6.生成用户的token
|
||||
// 7. 生成用户的token
|
||||
DefaultJwtPayload defaultJwtPayload = new DefaultJwtPayload(loginUser.getUserId(), loginUser.getAccount(), loginRequest.getRememberMe());
|
||||
String jwtToken = JwtContext.me().generateTokenDefaultPayload(defaultJwtPayload);
|
||||
|
||||
synchronized (SESSION_OPERATE_LOCK) {
|
||||
|
||||
// 7.缓存用户信息,创建会话
|
||||
// 8. 缓存用户信息,创建会话
|
||||
sessionManagerApi.createSession(jwtToken, loginUser);
|
||||
|
||||
// 8.如果开启了单账号单端在线,则踢掉已经上线的该用户
|
||||
// 9. 如果开启了单账号单端在线,则踢掉已经上线的该用户
|
||||
if (AuthConfigExpander.getSingleAccountLoginFlag()) {
|
||||
sessionManagerApi.removeSessionExcludeToken(jwtToken);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 9.更新用户登录时间和ip
|
||||
// 10. 更新用户登录时间和ip
|
||||
String ip = HttpServletUtil.getRequestClientIp(HttpServletUtil.getRequest());
|
||||
userServiceApi.updateUserLoginInfo(loginUser.getUserId(), new Date(), ip);
|
||||
|
||||
// 10.组装返回结果
|
||||
// 11. 组装返回结果
|
||||
return new LoginResponse(loginUser, jwtToken);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package cn.stylefeng.roses.kernel.auth.password;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.digest.BCrypt;
|
||||
import cn.stylefeng.roses.kernel.auth.api.password.PasswordStoredEncryptApi;
|
||||
|
||||
/**
|
||||
* 基于BCrypt算法实现的密码加密解密器
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/21 17:02
|
||||
*/
|
||||
public class BcryptPasswordStoredEncrypt implements PasswordStoredEncryptApi {
|
||||
|
||||
@Override
|
||||
public String encrypt(String originPassword) {
|
||||
if (StrUtil.isBlank(originPassword)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return BCrypt.hashpw(originPassword, BCrypt.gensalt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean checkPassword(String encryptBefore, String encryptAfter) {
|
||||
return BCrypt.checkpw(encryptBefore, encryptAfter);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package cn.stylefeng.roses.kernel.auth.password;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.asymmetric.KeyType;
|
||||
import cn.hutool.crypto.asymmetric.RSA;
|
||||
import cn.stylefeng.roses.kernel.auth.api.password.PasswordTransferEncryptApi;
|
||||
|
||||
/**
|
||||
* 基于RSA加密算法的,用于密码传输用的,密码加密解密器
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/21 17:02
|
||||
*/
|
||||
public class RsaPasswordTransferEncrypt implements PasswordTransferEncryptApi {
|
||||
|
||||
/**
|
||||
* rsa公钥
|
||||
*/
|
||||
private final String publicKey;
|
||||
|
||||
/**
|
||||
* RSA私钥
|
||||
*/
|
||||
private final String privateKey;
|
||||
|
||||
public RsaPasswordTransferEncrypt(String publicKey, String privateKey) {
|
||||
this.publicKey = publicKey;
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encrypt(String originPassword) {
|
||||
if (StrUtil.isBlank(originPassword)) {
|
||||
return null;
|
||||
}
|
||||
RSA rsa = new RSA(privateKey, publicKey);
|
||||
return rsa.encryptBase64(originPassword, KeyType.PublicKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String decrypt(String encryptedPassword) {
|
||||
RSA rsa = new RSA(privateKey, publicKey);
|
||||
return rsa.decryptStr(encryptedPassword, KeyType.PrivateKey);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,10 @@ package cn.stylefeng.roses.kernel.auth.starter;
|
|||
import cn.hutool.cache.CacheUtil;
|
||||
import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi;
|
||||
import cn.stylefeng.roses.kernel.auth.api.expander.AuthConfigExpander;
|
||||
import cn.stylefeng.roses.kernel.auth.api.password.PasswordStoredEncryptApi;
|
||||
import cn.stylefeng.roses.kernel.auth.api.password.PasswordTransferEncryptApi;
|
||||
import cn.stylefeng.roses.kernel.auth.password.BcryptPasswordStoredEncrypt;
|
||||
import cn.stylefeng.roses.kernel.auth.password.RsaPasswordTransferEncrypt;
|
||||
import cn.stylefeng.roses.kernel.auth.session.MemoryCacheSessionManager;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
@ -17,6 +21,30 @@ import org.springframework.context.annotation.Configuration;
|
|||
@Configuration
|
||||
public class GunsAuthAutoConfiguration {
|
||||
|
||||
/**
|
||||
* Bcrypt方式的密码加密
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/21 17:45
|
||||
*/
|
||||
@Bean
|
||||
public PasswordStoredEncryptApi passwordStoredEncryptApi() {
|
||||
return new BcryptPasswordStoredEncrypt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Bcrypt方式的密码加密
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/21 17:45
|
||||
*/
|
||||
@Bean
|
||||
public PasswordTransferEncryptApi passwordTransferEncryptApi() {
|
||||
String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCytSVn3ff7eBJckAFYwgJjqE9Zq2uAL4g+hkfQqGALdT8NJKALFxNzeSD/xTBLAJrtALWbN1dvyktoVNPAuuzCZO1BxYZNaAU3IKFaj73OSPzca5SGY0ibMw0KvEPkC3sZQeqBqx+VqYAqan90BeG/r9p36Eb0wrshj5XmsFeo6QIDAQAB";
|
||||
String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALK1JWfd9/t4ElyQAVjCAmOoT1mra4AviD6GR9CoYAt1Pw0koAsXE3N5IP/FMEsAmu0AtZs3V2/KS2hU08C67MJk7UHFhk1oBTcgoVqPvc5I/NxrlIZjSJszDQq8Q+QLexlB6oGrH5WpgCpqf3QF4b+v2nfoRvTCuyGPleawV6jpAgMBAAECgYBS9fUfetQcUWl0vwVhBu/FA+WSYxnMsEQ3gm7kVsX/i7Zxi4cgnt3QxXKkSg5ZQzaov6OPIuncY7UOAhMrbZtq/Hh8atdTVC/Ng/X9Bomodplq/+KTe/vIfWW5rlQAnMNFVaidxhCVRlRHNusapmj2vYwsiyI9kXUJNHryxtFC4QJBANtQuh3dtd79t3MVaC3TUD/EsGBe9TB3Eykbgv0muannC2Oq8Ci4vIp0NSA+FNCoB8ctgfKJUdBS8RLVnYyu3RcCQQDQmY+AuAXEpO9SgcYeRnQSOU2OSuC1wLt1MRVpPTdvE3bfRnkVxMrK0n3YilQWkQzfkERSG4kRFLIw605xPWn/AkEAiw3vQ9p8Yyu5MiXDjTKrchMyxZfPnHATXQANmJcCJ0DQDtymMxuWp66wtIXIStgPPnGTMAVzM0Qzh/6bS0Tf9wJAWj+1yFjVlghNyoJ+9qZAnYnRNhjLM5dZAxDjVI65pwLi0SKqTHLB0hJThBYE32aODUNba7KiEJPFrEiBvZh2fQJARbboHuHT0PqD1UTJGgodHlaw48kreBU+twext/9/jIqvwmFF88BmQgssHGW/tn4E6Qy3+rCCNWreEReY0gATYw==";
|
||||
return new RsaPasswordTransferEncrypt(publicKey, privateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认的session缓存为内存缓存,方便启动
|
||||
* <p>
|
||||
|
|
Loading…
Reference in New Issue