Springboot+oauth2.0实现微信登录(oauth2.0自定义授权模式) 您所在的位置:网站首页 oauthLogin和oauth2Client区别 Springboot+oauth2.0实现微信登录(oauth2.0自定义授权模式)

Springboot+oauth2.0实现微信登录(oauth2.0自定义授权模式)

2024-06-26 10:47| 来源: 网络整理| 查看: 265

1、前置准备参考 https://blog.csdn.net/qq_34190023/article/details/81133619 2、微信登录实现流程图 在这里插入图片描述 3、oauth自定义授权模式 上图大概描述了微信登录的一个流程。如果你是用oauth2.0,就会存在一个问题。oauth2.0自身支持四种授权模式,分别是:

authorization code(授权码模式)implicit(简化模式)resource owner password credentials(密码模式)client credentials(客户端模式)

前三种模式都需要用户的密码才能认证成功,客户端模式虽然不需要密码,但是也不会跟用户绑定。所以也是不符合的。我们去微信拿到用户的认证之后,需要自己的系统认证通过,然后返回token给前端。如果系统采用oauth2.0来做认证,这时候我们是没办法拿到用户的明文密码的。并且一般密码都是用BCryptPasswordEncoder加密处理,是不可逆的。这个时候,我们虽然通过了微信的认证,但是如何通过自身系统的认证就是个问题了。那么这时候就需要自定义oauth2.0的授权模式了,通过微信返回的用户唯一标识来完成认证。 注:自定义授权模式适用于任何第三方登录 附上核心代码:

/** * * 第三方登录验证filter */ public class SocialAuthenticationFilter extends AbstractAuthenticationProcessingFilter { private static final String SPRING_SECURITY_FORM_MOBILE_KEY = "social"; @Getter @Setter private String mobileParameter = SPRING_SECURITY_FORM_MOBILE_KEY; @Getter @Setter private boolean postOnly = true; @Getter @Setter private AuthenticationEventPublisher eventPublisher; @Getter @Setter private AuthenticationEntryPoint authenticationEntryPoint; public SocialAuthenticationFilter() { super(new AntPathRequestMatcher("/social/token", "POST")); } @Override @SneakyThrows public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) { if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) { throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } String mobile = obtainMobile(request); if (mobile == null) { mobile = ""; } mobile = mobile.trim(); SocialAuthenticationToken socialAuthenticationToken = new SocialAuthenticationToken(mobile); setDetails(request, socialAuthenticationToken); Authentication authResult = null; try { authResult = this.getAuthenticationManager().authenticate(socialAuthenticationToken); logger.debug("Authentication success: " + authResult); SecurityContextHolder.getContext().setAuthentication(authResult); } catch (Exception failed) { SecurityContextHolder.clearContext(); logger.debug("Authentication request failed: " + failed); eventPublisher.publishAuthenticationFailure(new BadCredentialsException(failed.getMessage(), failed), new PreAuthenticatedAuthenticationToken("access-token", "N/A")); try { authenticationEntryPoint.commence(request, response, new UsernameNotFoundException(failed.getMessage(), failed)); } catch (Exception e) { logger.error("authenticationEntryPoint handle error:{}", failed); } } return authResult; } private String obtainMobile(HttpServletRequest request) { return request.getParameter(mobileParameter); } private void setDetails(HttpServletRequest request, SocialAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } } /** * 社交登录 */ @Slf4j public class SocialAuthenticationProvider implements AuthenticationProvider { private MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); private UserDetailsChecker detailsChecker = new PreAuthenticationChecks(); @Getter @Setter private UserDetailsService socialUserDetailService; @Override @SneakyThrows public Authentication authenticate(Authentication authentication) { SocialAuthenticationToken socialAuthenticationToken = (SocialAuthenticationToken) authentication; String principal = socialAuthenticationToken.getPrincipal().toString(); UserDetails userDetails = socialUserDetailService.loadUserByUsername(principal); if (userDetails == null) { log.debug("Authentication failed: no credentials provided"); throw new BadCredentialsException(messages .getMessage("AbstractUserDetailsAuthenticationProvider.noopBindAccount", "Noop Bind Account")); } // 检查账号状态 detailsChecker.check(userDetails); SocialAuthenticationToken authenticationToken = new SocialAuthenticationToken(userDetails, userDetails.getAuthorities()); authenticationToken.setDetails(socialAuthenticationToken.getDetails()); return authenticationToken; } @Override public boolean supports(Class authentication) { return SocialAuthenticationToken.class.isAssignableFrom(authentication); } } /** * 第三方登录令牌 */ public class SocialAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; private final Object principal; public SocialAuthenticationToken(String mobile) { super(null); this.principal = mobile; setAuthenticated(false); } public SocialAuthenticationToken(Object principal, Collection authorities) { super(authorities); this.principal = principal; super.setAuthenticated(true); } @Override public Object getPrincipal() { return this.principal; } @Override public Object getCredentials() { return null; } @Override @SneakyThrows public void setAuthenticated(boolean isAuthenticated) { if (isAuthenticated) { throw new IllegalArgumentException( "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); } super.setAuthenticated(false); } @Override public void eraseCredentials() { super.eraseCredentials(); } } /** * * 第三方登录配置入口 */ @Getter @Setter public class SocialSecurityConfigurer extends SecurityConfigurerAdapter { @Autowired private ObjectMapper objectMapper; @Autowired private AuthenticationEventPublisher defaultAuthenticationEventPublisher; @Autowired private AuthenticationSuccessHandler socialLoginSuccessHandler; @Autowired private UserDetailsService socialUserDetailService; @Override public void configure(HttpSecurity http) { SocialAuthenticationFilter socialAuthenticationFilter = new SocialAuthenticationFilter(); socialAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); socialAuthenticationFilter.setAuthenticationSuccessHandler(socialLoginSuccessHandler); socialAuthenticationFilter.setEventPublisher(defaultAuthenticationEventPublisher); socialAuthenticationFilter.setAuthenticationEntryPoint(new ResourceAuthExceptionEntryPoint(objectMapper)); SocialAuthenticationProvider socialAuthenticationProvider = new SocialAuthenticationProvider(); socialAuthenticationProvider.setSocialUserDetailService(socialUserDetailService); http.authenticationProvider(socialAuthenticationProvider).addFilterAfter(socialAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); } } @Slf4j public class PreAuthenticationChecks implements UserDetailsChecker { private MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); @Override public void check(UserDetails user) { if (!user.isAccountNonLocked()) { log.debug("User account is locked"); throw new LockedException( messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked", "User account is locked")); } if (!user.isEnabled()) { log.debug("User account is disabled"); throw new DisabledException( messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled", "User is disabled")); } if (!user.isAccountNonExpired()) { log.debug("User account is expired"); throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired", "User account has expired")); } } }

附上测试请求示例:code对应微信返回用户唯一标识。即可完成本系统认证,拿到token。

Map params = new HashMap(); params.put("grant_type","social"); params.put("social",code); params.put("client_id","test"); params.put("client_secret","test"); String token = OkHttpUtils.doFromPost("http://localhost:端口号/auth/social/token", params);


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有