摘要:現在有一個需求就是改造實現手機號碼可以登錄需要重幾個類第一個類手機驗證碼登陸第二個類驗證碼驗證,調用公共服務查詢為的,并判斷其與驗證碼是否匹配第三個類第四個類第五個類不存在不匹配最后在配置一下設置禁止隱藏用戶未找到異常使用進行密碼
現在有一個需求就是改造 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... 來實現 本人已經驗證
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/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