package com.iplatform.security; import com.iplatform.base.PlatformLoginCallback; import com.iplatform.base.pojo.RequestLogin; import com.iplatform.security.exception.PcUserStopAppException; import com.iplatform.security.util.LoginCallbackUtils; import com.walker.web.CaptchaType; import com.walker.web.ClientType; import com.walker.web.LoginType; import com.walker.web.ResponseCode; import com.walker.web.UserType; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.InternalAuthenticationServiceException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; /** * 自定义认证提供者,由平台自己决定如何对比密码验证,如果不定制则spring会自动比较密码。 * @author 时克英 * @date 2023-01-28 */ public class DefaultAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { @Override protected void additionalAuthenticationChecks(UserDetails userDetails , UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { if(!(authentication instanceof DefaultAuthenticationToken)){ throw new InternalAuthenticationServiceException("UsernamePasswordAuthenticationToken 必须是: DefaultAuthenticationToken", null); } DefaultAuthenticationToken defaultAuthenticationToken = (DefaultAuthenticationToken)authentication; RequestLogin requestLogin = defaultAuthenticationToken.getRequestLogin(); // 非APP用户能否登录手机APP?可以在这里判断,2023-03-20 if(!this.allowPcUserAccessApp){ if(requestLogin.getClientType().equalsIgnoreCase(ClientType.MOBILE.getIndex())){ DefaultUserDetails defaultUserDetails = (DefaultUserDetails) userDetails; if(defaultUserDetails.getUserPrincipal().getUserInfo().getUser_type() != UserType.TYPE_APP_REG){ // 登录方式为移动端,同时用户类别为非app用户,禁止登录 throw new PcUserStopAppException(null); } } } // 通过登录类型,获取配置的登录回调对象,委派实现密码验证。 // 2023-12-28 移动端登录验证 CaptchaType captchaType = CaptchaType.getType(requestLogin.getVerifyType()); PlatformLoginCallback loginCallback = LoginCallbackUtils.getLoginCallbackBean(LoginType.getType(requestLogin.getLoginType()), true, captchaType); if(loginCallback == null){ throw new InternalAuthenticationServiceException("loginCallback未找到:" + requestLogin.getLoginType()); } boolean success = loginCallback.validatePassword(((DefaultUserDetails)userDetails).getUserPrincipal()); if(!success){ throw new BadCredentialsException(ResponseCode.USER_CREDENTIALS_ERROR.getMessage()); } logger.debug("++++++++++++ 自动验证密码为正确, loginType = " + requestLogin.getLoginType()); } @Override protected UserDetails retrieveUser(String username , UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { try{ UserDetails loadedUser = this.userDetailsService.loadUserByUsername(username); if(loadedUser == null){ throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation"); } return loadedUser; } catch (Exception ex){ if(ex instanceof UsernameNotFoundException){ logger.debug("+++++++++++++++ " + ex.getMessage()); throw ex; } if(ex instanceof InternalAuthenticationServiceException){ throw ex; } throw new InternalAuthenticationServiceException(ex.getMessage(), ex); } } public void setUserDetailsService(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } /** * 设置是否允许'后台PC用户'访问登录手机APP * @param allowPcUserAccessApp * @date 2023-03-20 */ public void setAllowPcUserAccessApp(boolean allowPcUserAccessApp) { this.allowPcUserAccessApp = allowPcUserAccessApp; } private boolean allowPcUserAccessApp = true; private UserDetailsService userDetailsService; }