摘要:现在有一个需求就是改造实现手机号码可以登录需要重几个类第一个类手机验证码登陆第二个类验证码验证,调用公共服务查询为的,并判断其与验证码是否匹配第三个类第四个类第五个类不存在不匹配最后在配置一下设置禁止隐藏用户未找到异常使用进行密码
现在有一个需求就是改造 oauth2.0 实现手机号码可以登录 需要重几个类
第一个类
public class PhoneLoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private static final String SPRING_SECURITY_RESTFUL_PHONE_KEY = "phone"; private static final String SPRING_SECURITY_RESTFUL_VERIFY_CODE_KEY = "verifyCode"; private static final String SPRING_SECURITY_RESTFUL_LOGIN_URL = "/oauth/phoneLogin"; private boolean postOnly = true; public PhoneLoginAuthenticationFilter() { super(new AntPathRequestMatcher(SPRING_SECURITY_RESTFUL_LOGIN_URL, "POST")); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException( "Authentication method not supported: " + request.getMethod()); } AbstractAuthenticationToken authRequest; String principal; String credentials; // 手机验证码登陆 principal = obtainParameter(request, SPRING_SECURITY_RESTFUL_PHONE_KEY); credentials = obtainParameter(request, SPRING_SECURITY_RESTFUL_VERIFY_CODE_KEY); principal = principal.trim(); authRequest = new PhoneAuthenticationToken(principal, credentials); // Allow subclasses to set the "details" property setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } private void setDetails(HttpServletRequest request, AbstractAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } private String obtainParameter(HttpServletRequest request, String parameter) { String result = request.getParameter(parameter); return result == null ? "" : result; }
第二个类
public class PhoneAuthenticationProvider extends MyAbstractUserDetailsAuthenticationProvider {
private UserDetailsService userDetailsService; @Override protected void additionalAuthenticationChecks(UserDetails var1, Authentication authentication) throws AuthenticationException { if(authentication.getCredentials() == null) { this.logger.debug("Authentication failed: no credentials provided"); throw new BadCredentialsException(this.messages.getMessage("PhoneAuthenticationProvider.badCredentials", "Bad credentials")); } else { String presentedPassword = authentication.getCredentials().toString(); // 验证码验证,调用公共服务查询 key 为authentication.getPrincipal()的value, 并判断其与验证码是否匹配 if(!"1000".equals(presentedPassword)){ this.logger.debug("Authentication failed: verifyCode does not match stored value"); throw new BadCredentialsException(this.messages.getMessage("PhoneAuthenticationProvider.badCredentials", "Bad verifyCode")); } } } @Override protected Authentication createSuccessAuthentication(Object principal, Authentication authentication, UserDetails user) { PhoneAuthenticationToken result = new PhoneAuthenticationToken(principal, authentication.getCredentials(), user.getAuthorities()); result.setDetails(authentication.getDetails()); return result; } @Override protected UserDetails retrieveUser(String phone, Authentication authentication) throws AuthenticationException { UserDetails loadedUser; try { loadedUser = this.getUserDetailsService().loadUserByUsername(phone); } catch (UsernameNotFoundException var6) { throw var6; } catch (Exception var7) { throw new InternalAuthenticationServiceException(var7.getMessage(), var7); } if(loadedUser == null) { throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation"); } else { return loadedUser; } } @Override public boolean supports(Class> authentication) { return PhoneAuthenticationToken.class.isAssignableFrom(authentication); } public UserDetailsService getUserDetailsService() { return userDetailsService; } public void setUserDetailsService(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; }
}
第三个类
@Service
public class PhoneUserDetailService implements UserDetailsService {
private Logger logger = LoggerFactory.getLogger(this.getClass()); @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { System.out.println("PhoneUserDetailService"); return new User("admin", "1000", AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER")); }
}
第四个类
public class PhoneAuthenticationToken extends MyAuthenticationToken {
public PhoneAuthenticationToken(Object principal, Object credentials) { super(principal, credentials); } public PhoneAuthenticationToken(Object principal, Object credentials, Collection extends GrantedAuthority> authorities) { super(principal, credentials, authorities); }
}
第五个类
@Component("MyLoginAuthSuccessHandler")
public class MyLoginAuthSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
@Autowired private ClientDetailsService clientDetailsService; @Autowired private AuthorizationServerTokenServices authorizationServerTokenServices; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
// String clientId = obtainParameter(request, "client_id");
// String client_secret = obtainParameter(request, "client_secret");
String header = request.getHeader("Authorization"); header.toLowerCase().startsWith("basic "); String[] strings = extractAndDecodeHeader(header, request); String clientId = strings[0]; String client_secret = strings[1]; String clientSecret = new BCryptPasswordEncoder().encode(client_secret); System.out.println(clientSecret); ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId); if (null == clientDetails) { throw new UnapprovedClientAuthenticationException("clientId不存在" + clientId); } else if (!new BCryptPasswordEncoder().matches(client_secret, clientDetails.getClientSecret())) { throw new UnapprovedClientAuthenticationException("clientSecret不匹配" + clientId); } TokenRequest tokenRequest = new TokenRequest(MapUtils.EMPTY_MAP, clientId, clientDetails.getScope(), "phone"); OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails); OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication); OAuth2AccessToken token = authorizationServerTokenServices.createAccessToken(oAuth2Authentication); Setscope = token.getScope(); StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(scope.stream().findFirst()); scope.stream().forEach(s -> { stringBuffer.append("," + s); }); Map map = new HashMap<>(); map.put("access_token", token.getValue()); map.put("token_type", token.getTokenType()); map.put("refresh_token", token.getRefreshToken().getValue()); map.put("expires_in", token.getExpiresIn()); map.put("scope", scope.stream().findFirst()); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write(JsonUtil.toJsonString(map)); } private String obtainParameter(HttpServletRequest request, String parameter) { String result = request.getParameter(parameter); return result == null ? "" : result; } private String[] extractAndDecodeHeader(String header, HttpServletRequest request) throws IOException { byte[] base64Token = header.substring(6).getBytes("UTF-8"); byte[] decoded; try { decoded = Base64.getDecoder().decode(base64Token); } catch (IllegalArgumentException e) { throw new BadCredentialsException( "Failed to decode basic authentication token"); } String token = new String(decoded, "UTF-8"); int delim = token.indexOf(":"); if (delim == -1) { throw new BadCredentialsException("Invalid basic authentication token"); } return new String[] { token.substring(0, delim), token.substring(delim + 1) }; }
}
最后在 SecurityConfig 配置一下
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired private SsoUserDetailsService ssoUserDetailsService; @Autowired private PhoneUserDetailService phoneUserDetailService; @Autowired private QrUserDetailService qrUserDetailService; @Autowired private MyLoginAuthSuccessHandler myLoginAuthSuccessHandler; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override public void configure(WebSecurity web) { web.ignoring().antMatchers("/authentication/require", "/**/*.js", "/**/*.css", "/**/*.jpg", "/**/*.png", "/**/*.woff2", "/oauth/exit", "/oauth/logout" ); } @Override protected void configure(HttpSecurity http) throws Exception { http .addFilterBefore(getPhoneLoginAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(getQrLoginAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) .formLogin().loginPage("/authentication/require") .loginProcessingUrl("/authentication/form") .successHandler(myLoginAuthSuccessHandler).and() .authorizeRequests().antMatchers("/authentication/require", "/authentication/form", "/**/*.js", "/**/*.css", "/**/*.jpg", "/**/*.png", "/**/*.woff2", "/auth/*", "/oauth/*", ) .permitAll() .anyRequest().authenticated().and().anonymous().disable().exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login?error")).and() .csrf().disable(); http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(phoneAuthenticationProvider()); auth.authenticationProvider(daoAuthenticationProvider()); } @Bean public DaoAuthenticationProvider daoAuthenticationProvider(){ DaoAuthenticationProvider provider1 = new DaoAuthenticationProvider(); // 设置userDetailsService provider1.setUserDetailsService(ssoUserDetailsService); // 禁止隐藏用户未找到异常 provider1.setHideUserNotFoundExceptions(false); // 使用BCrypt进行密码的hash provider1.setPasswordEncoder(passwordEncode()); return provider1; } @Bean public PhoneAuthenticationProvider phoneAuthenticationProvider(){ PhoneAuthenticationProvider provider = new PhoneAuthenticationProvider(); // 设置userDetailsService provider.setUserDetailsService(phoneUserDetailService); // 禁止隐藏用户未找到异常 provider.setHideUserNotFoundExceptions(false); return provider; } @Override @Bean public AuthenticationManager authenticationManager() throws Exception { return super.authenticationManager(); } /** * 手机验证码登陆过滤器 * @return */ @Bean public PhoneLoginAuthenticationFilter getPhoneLoginAuthenticationFilter() { PhoneLoginAuthenticationFilter filter = new PhoneLoginAuthenticationFilter(); try { filter.setAuthenticationManager(this.authenticationManagerBean()); } catch (Exception e) { e.printStackTrace(); } filter.setAuthenticationSuccessHandler(myLoginAuthSuccessHandler); filter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/login?error")); return filter; }
}
配置好了
本文代码参考 https://github.com/fp2952/spr... 来实现 本人已经验证
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/73061.html
摘要:验证码的发放校验逻辑比较简单,方法后通过全局判断请求中是否和手机号匹配集合,重点逻辑是令牌的参数 spring security oauth2 登录过程详解 showImg(https://segmentfault.com/img/remote/1460000012811024); 定义手机号登录令牌 /** * @author lengleng * @date 2018/...
摘要:前言基于做微服务架构分布式系统时,作为认证的业内标准,也提供了全套的解决方案来支持在环境下使用,提供了开箱即用的组件。 前言 基于SpringCloud做微服务架构分布式系统时,OAuth2.0作为认证的业内标准,Spring Security OAuth2也提供了全套的解决方案来支持在Spring Cloud/Spring Boot环境下使用OAuth2.0,提供了开箱即用的组件。但...
摘要:前言现在的好多项目都是基于移动端以及前后端分离的项目,之前基于的前后端放到一起的项目已经慢慢失宠并淡出我们视线,尤其是当基于的微服务架构以及单页面应用流行起来后,情况更甚。使用生成是什么请自行百度。 1、前言 现在的好多项目都是基于APP移动端以及前后端分离的项目,之前基于Session的前后端放到一起的项目已经慢慢失宠并淡出我们视线,尤其是当基于SpringCloud的微服务架构以及...
摘要:登录认证几乎是任何一个系统的标配,系统客户端等,好多都需要注册登录授权认证。假设我们开发了一个电商平台,并集成了微信登录,以这个场景为例,说一下的工作原理。微信网页授权是授权码模式的授权模式。 登录认证几乎是任何一个系统的标配,web 系统、APP、PC 客户端等,好多都需要注册、登录、授权认证。 场景说明 以一个电商系统,假设淘宝为例,如果我们想要下单,首先需要注册一个账号。拥有了账...
阅读 1164·2021-09-10 10:51
阅读 896·2019-08-30 15:53
阅读 2724·2019-08-30 12:50
阅读 976·2019-08-30 11:07
阅读 1990·2019-08-30 10:50
阅读 3598·2019-08-29 18:47
阅读 1308·2019-08-29 18:44
阅读 1599·2019-08-29 17:01