@@ -0,0 +1,39 @@ | |||
package com.hz.pm.api.user.security.auth.checker; | |||
import cn.hutool.core.collection.CollUtil; | |||
import com.hz.pm.api.user.model.enumeration.UserAvailableEnum; | |||
import com.hz.pm.api.user.security.exception.BizLoginException; | |||
import com.hz.pm.api.user.security.model.UserFullInfoDTO; | |||
import java.util.Objects; | |||
/** | |||
* <p> | |||
* UserLoginHelper | |||
* </p> | |||
* | |||
* @author WendyYang | |||
* @since 09:21 2024/9/6 | |||
*/ | |||
public class UserLoginChecker { | |||
private UserLoginChecker() { | |||
} | |||
public static void checkLoginAuth(UserFullInfoDTO user) { | |||
if (Objects.isNull(user)) { | |||
throw new BizLoginException("用户不存在"); | |||
} | |||
if (user.getMhUnitId() == null || user.getMhUnitId() < 0) { | |||
throw BizLoginException.wrap("暂无登录权限"); | |||
} | |||
if (UserAvailableEnum.DISABLE.equals(user.getAvailable())) { | |||
throw new BizLoginException("账号已禁用"); | |||
} | |||
if (CollUtil.isEmpty(user.getUserRoleList())) { | |||
throw new BizLoginException("账号未配置角色"); | |||
} | |||
} | |||
} |
@@ -1,20 +1,16 @@ | |||
package com.hz.pm.api.user.security.auth.code; | |||
import cn.hutool.core.collection.CollUtil; | |||
import com.hz.pm.api.common.helper.UserInfoHelper; | |||
import com.hz.pm.api.user.convert.UserInfoConvertor; | |||
import com.hz.pm.api.user.model.enumeration.UserAvailableEnum; | |||
import com.hz.pm.api.user.security.auth.checker.UserLoginChecker; | |||
import com.hz.pm.api.user.security.model.UserFullInfoDTO; | |||
import com.hz.pm.api.user.security.model.UserInfoDetails; | |||
import com.hz.pm.api.user.security.validate.CommonLoginException; | |||
import lombok.RequiredArgsConstructor; | |||
import org.springframework.security.core.userdetails.UserDetailsService; | |||
import org.springframework.security.core.userdetails.UsernameNotFoundException; | |||
import org.springframework.stereotype.Service; | |||
import java.util.Objects; | |||
/** | |||
* <p> | |||
* AuthCodeLoginUserDetailService | |||
@@ -32,17 +28,9 @@ public class AuthCodeLoginUserDetailService implements UserDetailsService { | |||
@Override | |||
public UserInfoDetails loadUserByUsername(String username) throws UsernameNotFoundException { | |||
Long userId = Long.parseLong(username); | |||
UserFullInfoDTO ufi = userInfoHelper.getUserFullInfo(userId); | |||
if (Objects.isNull(ufi)) { | |||
throw new UsernameNotFoundException("用户不存在"); | |||
} | |||
if (UserAvailableEnum.DISABLE.equals(ufi.getAvailable())) { | |||
throw new CommonLoginException("账号已禁用"); | |||
} | |||
if (CollUtil.isEmpty(ufi.getUserRoleList())) { | |||
throw new CommonLoginException("账号未配置角色"); | |||
} | |||
return UserInfoConvertor.convert(ufi); | |||
UserFullInfoDTO user = userInfoHelper.getUserFullInfo(userId); | |||
UserLoginChecker.checkLoginAuth(user); | |||
return UserInfoConvertor.convert(user); | |||
} | |||
} |
@@ -3,7 +3,7 @@ package com.hz.pm.api.user.security.auth.credential; | |||
import com.ningdatech.basic.exception.BizException; | |||
import com.hz.pm.api.user.model.enumeration.LoginTypeEnum; | |||
import com.hz.pm.api.user.security.model.WebRequestDetails; | |||
import com.hz.pm.api.user.security.validate.CommonLoginException; | |||
import com.hz.pm.api.user.security.exception.BizLoginException; | |||
import org.apache.commons.lang3.StringUtils; | |||
import org.springframework.http.HttpMethod; | |||
import org.springframework.security.authentication.AuthenticationServiceException; | |||
@@ -60,8 +60,8 @@ public class CredentialAuthFilter extends AbstractAuthenticationProcessingFilter | |||
CredentialAuthToken authRequest = new CredentialAuthToken(identifier, credential, loginType); | |||
authRequest.setDetails(new WebRequestDetails(request)); | |||
return this.getAuthenticationManager().authenticate(authRequest); | |||
} catch (CommonLoginException e) { | |||
throw new CommonLoginException(e.getMessage()); | |||
} catch (BizLoginException e) { | |||
throw new BizLoginException(e.getMessage()); | |||
} catch (BadCredentialsException | BizException e) { | |||
throw new BadCredentialsException(e.getMessage()); | |||
} catch (AuthenticationException e) { | |||
@@ -80,19 +80,19 @@ public class CredentialAuthFilter extends AbstractAuthenticationProcessingFilter | |||
switch (loginTypeEnum) { | |||
case DING_QR_LOGIN: { | |||
if (StringUtils.isBlank(credential)) { | |||
throw new CommonLoginException("浙政钉扫码登陆 授权码 不能为空 credential"); | |||
throw new BizLoginException("浙政钉扫码登陆 授权码 不能为空 credential"); | |||
} | |||
} | |||
break; | |||
case USERNAME_PASSWORD_LOGIN: { | |||
if (StringUtils.isBlank(identifier) || StringUtils.isBlank(credential)) { | |||
throw new CommonLoginException("账号密码登陆 账号密码不能为空 identifier credential"); | |||
throw new BizLoginException("账号密码登陆 账号密码不能为空 identifier credential"); | |||
} | |||
} | |||
break; | |||
case PHONE_VERIFICATION_CODE_LOGIN: { | |||
if (StringUtils.isBlank(identifier) || StringUtils.isBlank(credential)) { | |||
throw new CommonLoginException("手机号验证码登陆 手机号或验证码不能为空 identifier credential"); | |||
throw new BizLoginException("手机号验证码登陆 手机号或验证码不能为空 identifier credential"); | |||
} | |||
} | |||
break; | |||
@@ -5,7 +5,7 @@ import com.hz.pm.api.sms.helper.VerifyCodeCheckHelper; | |||
import com.hz.pm.api.user.model.enumeration.LoginTypeEnum; | |||
import com.hz.pm.api.user.security.auth.constants.SessionTimeConst; | |||
import com.hz.pm.api.user.security.auth.constants.UserDetailsServiceConstant; | |||
import com.hz.pm.api.user.security.validate.CommonLoginException; | |||
import com.hz.pm.api.user.security.exception.BizLoginException; | |||
import com.ningdatech.basic.exception.BizException; | |||
import org.springframework.security.authentication.AuthenticationProvider; | |||
import org.springframework.security.authentication.BadCredentialsException; | |||
@@ -46,7 +46,7 @@ public class CredentialAuthProvider implements AuthenticationProvider { | |||
// 校验短信验证码 | |||
boolean verificationResult = verifyCodeCheckHelper.verification(VerificationCodeType.LOGIN, principal, credentials); | |||
if (!verificationResult && !SessionTimeConst.UNIVERSAL_VERIFICATION_CODE.equals(credentials)) { | |||
throw new CommonLoginException("验证码错误"); | |||
throw new BizLoginException("验证码错误"); | |||
} | |||
} | |||
user = userDetailsService.loadUserByUsername(principal + UserDetailsServiceConstant.USER_DETAILS_SERVICE_SEPARATOR + loginTypeEnum.name()); | |||
@@ -8,7 +8,7 @@ import com.hz.pm.api.user.manage.UserInfoManage; | |||
import com.hz.pm.api.user.security.auth.constants.UserDetailsServiceConstant; | |||
import com.hz.pm.api.user.security.model.UserFullInfoDTO; | |||
import com.hz.pm.api.user.security.model.UserInfoDetails; | |||
import com.hz.pm.api.user.security.validate.CommonLoginException; | |||
import com.hz.pm.api.user.security.exception.BizLoginException; | |||
import lombok.RequiredArgsConstructor; | |||
import org.springframework.security.core.userdetails.UserDetailsService; | |||
import org.springframework.security.core.userdetails.UsernameNotFoundException; | |||
@@ -39,7 +39,7 @@ public class CredentialLoginUserDetailService implements UserDetailsService { | |||
case PHONE_VERIFICATION_CODE_LOGIN: { | |||
userFullInfo = userInfoManage.queryUserInfoInPhoneNoAuth(username); | |||
if (Objects.isNull(userFullInfo)) { | |||
throw new CommonLoginException("该手机号未绑定用户"); | |||
throw new BizLoginException("该手机号未绑定用户"); | |||
} | |||
} | |||
break; | |||
@@ -54,7 +54,7 @@ public class CredentialLoginUserDetailService implements UserDetailsService { | |||
case DING_QR_LOGIN: { | |||
userFullInfo = userInfoManage.queryUserInfoInAccountIdAuth(username); | |||
if (Objects.isNull(userFullInfo)) { | |||
throw new CommonLoginException("浙政钉账号无法登陆"); | |||
throw new BizLoginException("浙政钉账号无法登陆"); | |||
} | |||
} | |||
break; | |||
@@ -64,7 +64,7 @@ public class CredentialLoginUserDetailService implements UserDetailsService { | |||
} | |||
if (UserAvailableEnum.DISABLE.equals(userFullInfo.getAvailable())) { | |||
throw new CommonLoginException("该账号已被禁用"); | |||
throw new BizLoginException("该账号已被禁用"); | |||
} | |||
return UserInfoConvertor.convert(userFullInfo); | |||
} | |||
@@ -1,21 +1,18 @@ | |||
package com.hz.pm.api.user.security.auth.mh; | |||
import cn.hutool.core.collection.CollUtil; | |||
import cn.hutool.json.JSONUtil; | |||
import com.hz.pm.api.common.helper.UserInfoHelper; | |||
import com.hz.pm.api.user.convert.UserInfoConvertor; | |||
import com.hz.pm.api.user.security.auth.checker.UserLoginChecker; | |||
import com.hz.pm.api.user.security.model.UserFullInfoDTO; | |||
import com.hz.pm.api.user.security.model.UserInfoDetails; | |||
import com.ningdatech.basic.exception.BizException; | |||
import lombok.RequiredArgsConstructor; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.springframework.security.core.userdetails.UserDetailsService; | |||
import org.springframework.security.core.userdetails.UsernameNotFoundException; | |||
import org.springframework.stereotype.Service; | |||
import static com.hz.pm.api.user.model.enumeration.UserAvailableEnum.DISABLE; | |||
/** | |||
* <p> | |||
* AgentLoginUserDetailService | |||
@@ -34,14 +31,7 @@ public class MhLoginUserDetailService implements UserDetailsService { | |||
@Override | |||
public UserInfoDetails loadUserByUsername(String username) throws UsernameNotFoundException { | |||
UserFullInfoDTO userInfo = userInfoHelper.getUserFullInfoByMhUserIdOrOpenId(username); | |||
if (userInfo == null || DISABLE.equals(userInfo.getAvailable())) { | |||
throw BizException.wrap("用户不存在或已被禁用"); | |||
} | |||
if (userInfo.getMhUnitId() == null | |||
|| userInfo.getMhUnitId() <= 0 | |||
|| CollUtil.isEmpty(userInfo.getUserRoleList())) { | |||
throw BizException.wrap("用户暂无登录权限"); | |||
} | |||
UserLoginChecker.checkLoginAuth(userInfo); | |||
log.info("登录用户为:{}", JSONUtil.toJsonStr(userInfo)); | |||
return UserInfoConvertor.convert(userInfo); | |||
} | |||
@@ -0,0 +1,20 @@ | |||
package com.hz.pm.api.user.security.exception; | |||
import org.springframework.security.core.AuthenticationException; | |||
/** | |||
* @author liuxinxin | |||
* @date 2023/3/24 上午11:47 | |||
* 通用登陆错误 | |||
*/ | |||
public class BizLoginException extends AuthenticationException { | |||
public BizLoginException(String message) { | |||
super(message); | |||
} | |||
public static BizLoginException wrap(String message) { | |||
return new BizLoginException(message); | |||
} | |||
} |
@@ -5,6 +5,7 @@ import com.hz.pm.api.user.security.errorcode.AuthErrorCodeEnum; | |||
import com.ningdatech.basic.model.ApiResponse; | |||
import lombok.RequiredArgsConstructor; | |||
import org.springframework.http.HttpStatus; | |||
import org.springframework.http.MediaType; | |||
import org.springframework.security.web.session.SessionInformationExpiredEvent; | |||
import org.springframework.security.web.session.SessionInformationExpiredStrategy; | |||
import org.springframework.stereotype.Component; | |||
@@ -13,10 +14,13 @@ import javax.servlet.http.HttpServletResponse; | |||
import java.io.IOException; | |||
/** | |||
* @Author LiuXinXin | |||
* @Date 2020/8/20 11:15 上午 | |||
* @Version 1.0 | |||
**/ | |||
* <p> | |||
* DefaultExpiredSessionStrategy | |||
* </p> | |||
* | |||
* @author WendyYang | |||
* @since 09:33 2024/9/6 | |||
*/ | |||
@Component | |||
@RequiredArgsConstructor | |||
public class DefaultExpiredSessionStrategy implements SessionInformationExpiredStrategy { | |||
@@ -27,11 +31,11 @@ public class DefaultExpiredSessionStrategy implements SessionInformationExpiredS | |||
@Override | |||
public void onExpiredSessionDetected(SessionInformationExpiredEvent sessionInformationExpiredEvent) | |||
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) | |||
throws IOException { | |||
HttpServletResponse response = sessionInformationExpiredEvent.getResponse(); | |||
HttpServletResponse response = event.getResponse(); | |||
response.setStatus(HttpStatus.UNAUTHORIZED.value()); | |||
response.setContentType("application/json;charset=UTF-8"); | |||
response.setContentType(MediaType.APPLICATION_JSON_VALUE); | |||
response.getWriter().write(objectMapper.writeValueAsString(SESSION_EXPIRED)); | |||
} | |||
@@ -1,29 +1,33 @@ | |||
package com.hz.pm.api.user.security.handler; | |||
import com.fasterxml.jackson.databind.ObjectMapper; | |||
import com.ningdatech.basic.model.ApiResponse; | |||
import com.hz.pm.api.user.security.errorcode.AuthErrorCodeEnum; | |||
import com.hz.pm.api.user.security.validate.CommonLoginException; | |||
import com.hz.pm.api.user.security.exception.BizLoginException; | |||
import com.ningdatech.basic.model.ApiResponse; | |||
import lombok.RequiredArgsConstructor; | |||
import org.springframework.security.authentication.BadCredentialsException; | |||
import org.springframework.security.core.AuthenticationException; | |||
import org.springframework.security.core.userdetails.UsernameNotFoundException; | |||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; | |||
import org.springframework.stereotype.Component; | |||
import javax.servlet.ServletException; | |||
import javax.servlet.http.HttpServletRequest; | |||
import javax.servlet.http.HttpServletResponse; | |||
import java.io.IOException; | |||
/** | |||
* @Author LiuXinXin | |||
* @Date 2020/8/3 8:32 下午 | |||
* @Version 1.0 | |||
**/ | |||
* <p> | |||
* DefaultLoginFailureHandler | |||
* </p> | |||
* | |||
* @author WendyYang | |||
* @since 09:36 2024/9/6 | |||
*/ | |||
@RequiredArgsConstructor | |||
@Component("defaultLoginFailureHandler") | |||
public class DefaultLoginFailureHandler extends SimpleUrlAuthenticationFailureHandler { | |||
private final ObjectMapper objectMapper = new ObjectMapper(); | |||
private final ObjectMapper objectMapper; | |||
@Override | |||
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, | |||
@@ -33,7 +37,7 @@ public class DefaultLoginFailureHandler extends SimpleUrlAuthenticationFailureHa | |||
String errorMsg; | |||
// 所有的认证异常都可以在这里添加,目前只支持用户名密码错误异常 | |||
if (exception instanceof CommonLoginException) { | |||
if (exception instanceof BizLoginException) { | |||
errorCode = 400; | |||
errorMsg = exception.getMessage(); | |||
} else if (exception instanceof BadCredentialsException || exception instanceof UsernameNotFoundException) { | |||
@@ -2,7 +2,7 @@ package com.hz.pm.api.user.security.handler; | |||
import com.fasterxml.jackson.databind.ObjectMapper; | |||
import com.ningdatech.basic.model.ApiResponse; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import lombok.RequiredArgsConstructor; | |||
import org.springframework.context.annotation.Primary; | |||
import org.springframework.http.MediaType; | |||
import org.springframework.security.core.Authentication; | |||
@@ -14,16 +14,19 @@ import javax.servlet.http.HttpServletResponse; | |||
import java.io.IOException; | |||
/** | |||
* @Author LiuXinXin | |||
* @Date 2020/8/3 8:32 下午 | |||
* @Version 1.0 | |||
**/ | |||
@Component("defaultLoginSuccessHandler") | |||
* <p> | |||
* DefaultLoginSuccessHandler | |||
* </p> | |||
* | |||
* @author WendyYang | |||
* @since 09:35 2024/9/6 | |||
*/ | |||
@Primary | |||
@RequiredArgsConstructor | |||
@Component("defaultLoginSuccessHandler") | |||
public class DefaultLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { | |||
@Autowired | |||
private ObjectMapper objectMapper; | |||
private final ObjectMapper objectMapper; | |||
@Override | |||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, | |||
@@ -1,17 +0,0 @@ | |||
package com.hz.pm.api.user.security.validate; | |||
import org.springframework.security.core.AuthenticationException; | |||
/** | |||
* @author liuxinxin | |||
* @date 2023/3/24 上午11:47 | |||
* 通用登陆错误 | |||
*/ | |||
public class CommonLoginException extends AuthenticationException { | |||
public CommonLoginException(String message) { | |||
super(message); | |||
} | |||
} |
@@ -1,24 +0,0 @@ | |||
package com.hz.pm.api.user.security.validate; | |||
import lombok.Data; | |||
import lombok.EqualsAndHashCode; | |||
/** | |||
* @author liuxinxin | |||
* @date 2023/3/24 上午11:47 | |||
* 浙政钉扫码登陆错误 | |||
*/ | |||
@Data | |||
@EqualsAndHashCode(callSuper = true) | |||
public class DingQrLoginException extends RuntimeException { | |||
private final Integer code; | |||
private final String message; | |||
public DingQrLoginException(int code, String message) { | |||
this.code = code; | |||
this.message = message; | |||
} | |||
} |
@@ -2,6 +2,7 @@ server: | |||
port: 8002 | |||
servlet: | |||
context-path: /hzpm | |||
shutdown: graceful | |||
spring: | |||
mvc: | |||
@@ -6,6 +6,7 @@ server: | |||
tomcat: | |||
threads: | |||
max: 600 | |||
shutdown: graceful | |||
spring: | |||
mvc: | |||
pathmatch: | |||