SpringSecurity和oauth2微信登陆
唐某 2023-05-04 13:41:22 2023-05-04 0 0
对于SpringSecurity和oauth2的初学者来说,实现微信单点登录可能会比较困难,以下是参考代码:
1.在pom.xml文件中添加以下依赖:
<dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>2.2.1.RELEASE</version></dependency><dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> <version>1.0.10.RELEASE</version></dependency>`
2.在application.properties文件中添加以下配置:
#微信公众号的appidwechat.appid=your wechat appid#微信公众号的appsecretwechat.secret=your wechat secret#微信登录授权回调地址wechat.redirect_uri=your redirect uri
3.创建WechatAuthenticationFilter过滤器,在该过滤器中实现微信登录的相关逻辑。逻辑如下:
- 判断请求是否为微信授权回调。
- 根据code值获取openid、access_token等信息。
- 判断该openid是否已在系统中绑定过账号,如果绑定过,则直接返回jwt token,否则返回错误码。
public class WechatAuthenticationFilter extends AbstractAuthenticationProcessingFilter { private final Logger logger = LoggerFactory.getLogger(getClass()); private static final String WECHAT_AUTHENTICATE_URL = "/wechat/login/authenticate"; private final Cache cache; @Autowired private WechatProperties wechatProperties; public WechatAuthenticationFilter(RequestMatcher requiresAuthenticationRequestMatcher, Cache cache) { super(requiresAuthenticationRequestMatcher); this.cache = cache; } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { logger.info("微信登录鉴权"); String code = request.getParameter("code"); if (StringUtils.isBlank(code)) { throw new WechatAuthenticationException(ErrorCodeEnum.WECHAT_AUTH_CODE_REQUIRED.getErrorCode(), ErrorCodeEnum.WECHAT_AUTH_CODE_REQUIRED.getErrorMsg()); } WechatAuthUserInfo wechatAuthUserInfo = WechatAuthUtils.getUserInfoByCodeAndAccessToken( code, wechatProperties.getAppid(), wechatProperties.getSecret()); // 检查是否已绑定用户 String openid = wechatAuthUserInfo.getOpenid(); UserAccountDao mainUserDao = BeanUtils.getBean(UserAccountDao.class); UserAccount userAccount = mainUserDao.getByOpenid(openid); if (userAccount == null) { throw new WechatAuthenticationException( ErrorCodeEnum.WECHAT_AUTH_OPENID_NOT_BIND.getErrorCode(), ErrorCodeEnum.WECHAT_AUTH_OPENID_NOT_BIND.getErrorMsg()); } logger.info("微信登录鉴权成功"); // 生成jwt token并返回 JwtTokenProperties jwtTokenProperties = BeanUtils.getBean(JwtTokenProperties.class); String token = JwtUtils.createToken(userAccount, jwtTokenProperties.getExpireInMinute(), jwtTokenProperties.getSecret()); response.setHeader("Access-Token", token); return new WechatAuthenticationToken(userAccount); } /** * 匹配url是否是微信授权回调 * * @param request * 请求 * @return boolean */ @Override protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) { return StringUtils.endsWith(request.getRequestURI(), WECHAT_AUTHENTICATE_URL) && request .getMethod().equalsIgnoreCase("get"); }}
4.创建WechatAuthenticationProvider提供器,用于保存登录状态和返回JWT token。
public class WechatAuthenticationProvider implements AuthenticationProvider { @Autowired private Cache cache; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { WechatAuthenticationToken wechatAuthenticationToken = (WechatAuthenticationToken) authentication; UserAccount userAccount = wechatAuthenticationToken.getUserAccount(); cache.put(userAccount.getUuid(), userAccount); return wechatAuthenticationToken; } @Override public boolean supports(Class<?> authentication) { return WechatAuthenticationToken.class.equals(authentication); }}
5.创建WechatAuthenticationToken类和WechatAuthenticationException类。
public class WechatAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = -2872688686791428001L; private final UserAccount userAccount; public WechatAuthenticationToken(UserAccount userAccount) { super(null); this.userAccount = userAccount; super.setAuthenticated(true); } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return Collections.emptyList(); } @Override public Object getCredentials() { return null; } @Override public Object getPrincipal() { return userAccount; } public UserAccount getUserAccount() { return userAccount; }}
public class WechatAuthenticationException extends AuthenticationException { private static final long serialVersionUID = 3045924610355703429L; private String errorCode; public WechatAuthenticationException(String errorCode, String message) { super(message); this.errorCode = errorCode; } public String getErrorCode() { return errorCode; } public void setErrorCode(String errorCode) { this.errorCode = errorCode; }}
6.创建WebSecurityConfigurerAdapter类,使过滤器和提供器生效。
@Configuration@EnableWebSecuritypublic class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Autowired private Cache cache; @Autowired private WechatAuthenticationProvider wechatAuthenticationProvider; @Autowired private JwtAuthenticationFilter jwtAuthenticationFilter; @Autowired private WechatProperties wechatProperties; @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() // 关闭csrf .authorizeRequests().antMatchers("/wechat/**").permitAll() // 微信登录授权 .antMatchers("/**").authenticated() // 其他接口需要登陆 .and().anonymous().disable().exceptionHandling() .authenticationEntryPoint(new RestAuthenticationEntryPoint()) .and() .addFilterBefore(wechatAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) // 微信授权登录过滤器 .addFilterBefore(jwtAuthenticationFilter, RequestCacheAwareFilter.class); // jwt验证过滤器 } @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/static/**"); super.configure(web); } @Bean public WechatAuthenticationFilter wechatAuthenticationFilter() { String wechatRedirectUri = wechatProperties.getRedirectUri(); String wechatAuthorizeUrl = WechatAuthUtils.generateAuthorizeUrl(wechatProperties.getAppid(), URLEncoder.encode(wechatRedirectUri), WechatAuthScopeEnum.SNSAPI_USERINFO); return new WechatAuthenticationFilter( new AntPathRequestMatcher(WECHAT_AUTHENTICATE_URL), cache); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(wechatAuthenticationProvider) .userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }}
以上就是在SpringSecurity + oauth2中使用微信单点登录的详细代码。