From 41a0c63739a74e6a5cafa70cd6705b9b1d5e351e Mon Sep 17 00:00:00 2001 From: liuxinxin Date: Tue, 14 Feb 2023 11:23:56 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=85=A5=20=E6=B5=99=E6=94=BF?= =?UTF-8?q?=E9=92=89=E6=89=AB=E7=A0=81=E7=99=BB=E9=99=86=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/credential/CredentialAuthFilter.java | 108 +++++++++++++++++++++ .../auth/credential/CredentialAuthProvider.java | 92 ++++++++++++++++++ .../credential/CredentialAuthSecurityConfig.java | 14 +-- .../credential/UsernamePasswordAuthFilter.java | 104 -------------------- .../credential/UsernamePasswordAuthProvider.java | 92 ------------------ 5 files changed, 207 insertions(+), 203 deletions(-) create mode 100644 pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthFilter.java create mode 100644 pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthProvider.java delete mode 100644 pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/UsernamePasswordAuthFilter.java delete mode 100644 pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/UsernamePasswordAuthProvider.java diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthFilter.java b/pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthFilter.java new file mode 100644 index 0000000..1ecfa09 --- /dev/null +++ b/pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthFilter.java @@ -0,0 +1,108 @@ +package com.ningdatech.pmapi.user.security.auth.credential; + +import com.ningdatech.basic.exception.BizException; +import com.ningdatech.pmapi.user.constant.LoginTypeEnum; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.InternalAuthenticationServiceException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * @Author LiuXinXin + * @Date 2020/8/3 8:46 下午 + * @Version 1.0 + **/ +public class CredentialAuthFilter extends AbstractAuthenticationProcessingFilter { + + private boolean postOnly = true; + + private static final String IDENTIFIER_PARAMETER = "identifier"; + private static final String CREDENTIAL_PARAMETER = "credential"; + private static final String LOGIN_TYPE_PARAMETER = "loginType"; + + + // ~ Constructors + // =================================================================================================== + + public CredentialAuthFilter(String processingUrl) { + super(new AntPathRequestMatcher(processingUrl, HttpMethod.POST.name())); + } + + // ~ Methods + // ======================================================================================================== + + @Override + public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) + throws AuthenticationException { + if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) { + throw new AuthenticationServiceException("请求方法错误"); + } + String identifier = request.getParameter(IDENTIFIER_PARAMETER); + String credential = request.getParameter(CREDENTIAL_PARAMETER); + String loginType = request.getParameter(LOGIN_TYPE_PARAMETER); + if (StringUtils.isBlank(loginType)) { + throw new BadCredentialsException("登陆类型不能为空"); + } + paramValid(identifier, credential, loginType); + + + identifier = trim(identifier); + credential = trim(credential); + loginType = trim(loginType); + try { + CredentialAuthToken authRequest = new CredentialAuthToken(identifier, credential, loginType); + // Allow subclasses to set the "details" property + setDetails(request, authRequest); + return this.getAuthenticationManager().authenticate(authRequest); + } catch (AuthenticationException e) { + throw new BadCredentialsException("账号或密码错误"); + } catch (BizException e) { + throw new BadCredentialsException(e.getMessage()); + } catch (Exception e) { + throw new InternalAuthenticationServiceException("授权失败:", e); + } + } + + protected void setDetails(HttpServletRequest request, CredentialAuthToken authRequest) { + authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); + } + + private void paramValid(String identifier, String credential, String loginType) { + LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(loginType); + switch (loginTypeEnum) { + case DING_QR_LOGIN: { + if (StringUtils.isBlank(credential)) { + throw new BadCredentialsException("浙政钉扫码登陆 授权码 不能为空 credential"); + } + } + break; + case USERNAME_PASSWORD_LOGIN: { + if (StringUtils.isBlank(identifier) || StringUtils.isBlank(credential)) { + throw new BadCredentialsException("账号密码登陆 账号密码不能为空 identifier credential"); + } + } + break; + case PHONE_VERIFICATION_CODE_LOGIN: { + if (StringUtils.isBlank(identifier) || StringUtils.isBlank(credential)) { + throw new BadCredentialsException("手机号验证码登陆 手机号或验证码不能为空 identifier credential"); + } + } + break; + } + } + + private String trim(String trimStr) { + if (StringUtils.isNotBlank(trimStr)) { + return trimStr.trim(); + } + return null; + } +} diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthProvider.java b/pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthProvider.java new file mode 100644 index 0000000..e4a5a69 --- /dev/null +++ b/pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthProvider.java @@ -0,0 +1,92 @@ +package com.ningdatech.pmapi.user.security.auth.credential; + +import com.ningdatech.pmapi.user.constant.LoginTypeEnum; +import com.ningdatech.zwdd.client.ZwddAuthClient; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.InternalAuthenticationServiceException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.PasswordEncoder; + +/** + * @Author LiuXinXin + * @Date 2020/8/3 8:55 下午 + * @Version 1.0 + **/ +public class CredentialAuthProvider implements AuthenticationProvider { + + private UserDetailsService userDetailsService; + + private PasswordEncoder passwordEncoder; + + private ZwddAuthClient zwddAuthClient; + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + if (!(authentication instanceof CredentialAuthToken)) { + throw new RuntimeException("CustomAuthProvider 只支持 CustomAuthToken"); + } + CredentialAuthToken authenticationToken = (CredentialAuthToken) authentication; + String credentials = (String) authenticationToken.getCredentials(); + + UserDetails user = null; + LoginTypeEnum loginTypeEnum = authenticationToken.getLoginTypeEnum(); + switch (loginTypeEnum) { + case DING_QR_LOGIN: { + // TODO 补充浙政钉扫码逻辑 + user = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal()); + } + break; + case PHONE_VERIFICATION_CODE_LOGIN: { + // TODO + user = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal()); + } + break; + case USERNAME_PASSWORD_LOGIN: { + user = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal()); + if (user == null) { + throw new InternalAuthenticationServiceException("can not get user info!"); + } + // 账号密码登陆 更改 + additionalAuthenticationChecks(user, authenticationToken); + } + break; + } + + + // 将用户定义的user放入token中,这样可以在session中查询到所有自定义的用户信息 + return new CredentialAuthToken(user, user.getPassword(), user.getAuthorities()); + } + + protected void additionalAuthenticationChecks(UserDetails userDetails, CredentialAuthToken authentication) + throws AuthenticationException { + if (authentication.getCredentials() == null) { + throw new BadCredentialsException("login fail! password is null"); + } + String presentedPassword = authentication.getCredentials().toString(); + if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) { + throw new BadCredentialsException("login fail! password is error"); + } + } + + @Override + public boolean supports(Class authentication) { + return CredentialAuthToken.class.isAssignableFrom(authentication); + } + + public void setUserDetailsService(UserDetailsService userDetailsService) { + this.userDetailsService = userDetailsService; + } + + public void setPasswordEncoder(PasswordEncoder passwordEncoder) { + this.passwordEncoder = passwordEncoder; + } + + public void setZwddAuthClient(ZwddAuthClient zwddAuthClient) { + this.zwddAuthClient = zwddAuthClient; + } + +} diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthSecurityConfig.java b/pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthSecurityConfig.java index 56b7432..332cfb1 100644 --- a/pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthSecurityConfig.java +++ b/pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/CredentialAuthSecurityConfig.java @@ -47,21 +47,21 @@ public class CredentialAuthSecurityConfig @Override public void configure(HttpSecurity http) throws Exception { - UsernamePasswordAuthFilter usernamePasswordAuthFilter = - new UsernamePasswordAuthFilter(authProperties.getPasswordLoginUrl()); + CredentialAuthFilter credentialAuthFilter = + new CredentialAuthFilter(authProperties.getPasswordLoginUrl()); authenticationManager = http.getSharedObject(AuthenticationManager.class); - usernamePasswordAuthFilter.setAuthenticationManager(authenticationManager); - usernamePasswordAuthFilter.setAuthenticationSuccessHandler(defaultLoginSuccessHandler); - usernamePasswordAuthFilter.setAuthenticationFailureHandler(defaultLoginFailureHandler); + credentialAuthFilter.setAuthenticationManager(authenticationManager); + credentialAuthFilter.setAuthenticationSuccessHandler(defaultLoginSuccessHandler); + credentialAuthFilter.setAuthenticationFailureHandler(defaultLoginFailureHandler); - UsernamePasswordAuthProvider authenticationProvider = new UsernamePasswordAuthProvider(); + CredentialAuthProvider authenticationProvider = new CredentialAuthProvider(); authenticationProvider.setUserDetailsService(credentialLoginUserDetailService); // 确保对密码进行加密的encoder和解密的encoder相同 authenticationProvider.setPasswordEncoder(passwordEncoder); // 传入浙政钉client authenticationProvider.setZwddAuthClient(zwddAuthClient); - http.authenticationProvider(authenticationProvider).addFilterAfter(usernamePasswordAuthFilter, + http.authenticationProvider(authenticationProvider).addFilterAfter(credentialAuthFilter, UsernamePasswordAuthenticationFilter.class); } diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/UsernamePasswordAuthFilter.java b/pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/UsernamePasswordAuthFilter.java deleted file mode 100644 index 1863b4a..0000000 --- a/pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/UsernamePasswordAuthFilter.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.ningdatech.pmapi.user.security.auth.credential; - -import com.ningdatech.basic.exception.BizException; -import com.ningdatech.pmapi.user.constant.LoginTypeEnum; -import org.apache.commons.lang3.StringUtils; -import org.springframework.http.HttpMethod; -import org.springframework.security.authentication.AuthenticationServiceException; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.authentication.InternalAuthenticationServiceException; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * @Author LiuXinXin - * @Date 2020/8/3 8:46 下午 - * @Version 1.0 - **/ -public class UsernamePasswordAuthFilter extends AbstractAuthenticationProcessingFilter { - - private boolean postOnly = true; - - private static final String IDENTIFIER_PARAMETER = "identifier"; - private static final String CREDENTIAL_PARAMETER = "credential"; - private static final String LOGIN_TYPE_PARAMETER = "loginType"; - - - // ~ Constructors - // =================================================================================================== - - public UsernamePasswordAuthFilter(String processingUrl) { - super(new AntPathRequestMatcher(processingUrl, HttpMethod.POST.name())); - } - - // ~ Methods - // ======================================================================================================== - - @Override - public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) - throws AuthenticationException { - if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) { - throw new AuthenticationServiceException("请求方法错误"); - } - String identifier = request.getParameter(IDENTIFIER_PARAMETER); - String credential = request.getParameter(CREDENTIAL_PARAMETER); - String loginType = request.getParameter(LOGIN_TYPE_PARAMETER); - if (StringUtils.isBlank(loginType)) { - throw new BadCredentialsException("登陆类型不能为空"); - } - - if (StringUtils.isBlank(identifier) || StringUtils.isBlank(credential)) { - throw new UsernameNotFoundException("用户名或密码不能为空"); - } - - identifier = identifier.trim(); - credential = credential.trim(); - loginType = loginType.trim(); - try { - CredentialAuthToken authRequest = new CredentialAuthToken(identifier, credential, loginType); - // Allow subclasses to set the "details" property - setDetails(request, authRequest); - return this.getAuthenticationManager().authenticate(authRequest); - } catch (AuthenticationException e) { - throw new BadCredentialsException("账号或密码错误"); - } catch (BizException e) { - throw new BadCredentialsException(e.getMessage()); - } catch (Exception e) { - throw new InternalAuthenticationServiceException("授权失败:", e); - } - } - - protected void setDetails(HttpServletRequest request, CredentialAuthToken authRequest) { - authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); - } - - private void valid(String identifier, String credential, String loginType) { - LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(loginType); - switch (loginTypeEnum) { - case DING_QR_LOGIN: { - if (StringUtils.isBlank(credential)) { - throw new BadCredentialsException("浙政钉扫码登陆 授权码 不能为空 credential"); - } - } - break; - case USERNAME_PASSWORD_LOGIN: { - if (StringUtils.isBlank(identifier) || StringUtils.isBlank(credential)) { - throw new BadCredentialsException("账号密码登陆 账号密码不能为空 identifier credential"); - } - } - break; - case PHONE_VERIFICATION_CODE_LOGIN: { - if (StringUtils.isBlank(identifier) || StringUtils.isBlank(credential)) { - throw new BadCredentialsException("手机号验证码登陆 手机号或验证码不能为空 identifier credential"); - } - } - break; - } - } -} diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/UsernamePasswordAuthProvider.java b/pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/UsernamePasswordAuthProvider.java deleted file mode 100644 index e8c6977..0000000 --- a/pmapi/src/main/java/com/ningdatech/pmapi/user/security/auth/credential/UsernamePasswordAuthProvider.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.ningdatech.pmapi.user.security.auth.credential; - -import com.ningdatech.pmapi.user.constant.LoginTypeEnum; -import com.ningdatech.zwdd.client.ZwddAuthClient; -import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.authentication.InternalAuthenticationServiceException; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.crypto.password.PasswordEncoder; - -/** - * @Author LiuXinXin - * @Date 2020/8/3 8:55 下午 - * @Version 1.0 - **/ -public class UsernamePasswordAuthProvider implements AuthenticationProvider { - - private UserDetailsService userDetailsService; - - private PasswordEncoder passwordEncoder; - - private ZwddAuthClient zwddAuthClient; - - @Override - public Authentication authenticate(Authentication authentication) throws AuthenticationException { - if (!(authentication instanceof CredentialAuthToken)) { - throw new RuntimeException("CustomAuthProvider 只支持 CustomAuthToken"); - } - CredentialAuthToken authenticationToken = (CredentialAuthToken) authentication; - String credentials = (String) authenticationToken.getCredentials(); - - UserDetails user = null; - LoginTypeEnum loginTypeEnum = authenticationToken.getLoginTypeEnum(); - switch (loginTypeEnum) { - case DING_QR_LOGIN: { - // TODO 补充浙政钉扫码逻辑 - user = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal()); - } - break; - case PHONE_VERIFICATION_CODE_LOGIN: { - // TODO - user = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal()); - } - break; - case USERNAME_PASSWORD_LOGIN: { - user = userDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal()); - if (user == null) { - throw new InternalAuthenticationServiceException("can not get user info!"); - } - // 账号密码登陆 更改 - additionalAuthenticationChecks(user, authenticationToken); - } - break; - } - - - // 将用户定义的user放入token中,这样可以在session中查询到所有自定义的用户信息 - return new CredentialAuthToken(user, user.getPassword(), user.getAuthorities()); - } - - protected void additionalAuthenticationChecks(UserDetails userDetails, CredentialAuthToken authentication) - throws AuthenticationException { - if (authentication.getCredentials() == null) { - throw new BadCredentialsException("login fail! password is null"); - } - String presentedPassword = authentication.getCredentials().toString(); - if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) { - throw new BadCredentialsException("login fail! password is error"); - } - } - - @Override - public boolean supports(Class authentication) { - return CredentialAuthToken.class.isAssignableFrom(authentication); - } - - public void setUserDetailsService(UserDetailsService userDetailsService) { - this.userDetailsService = userDetailsService; - } - - public void setPasswordEncoder(PasswordEncoder passwordEncoder) { - this.passwordEncoder = passwordEncoder; - } - - public void setZwddAuthClient(ZwddAuthClient zwddAuthClient) { - this.zwddAuthClient = zwddAuthClient; - } - -}