登录/注册
唐某
11055
占位
7
占位
31
浏览量
占位
粉丝
占位
关注
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文件中添加以下配置:

#微信公众号的appid
wechat.appid=your wechat appid
#微信公众号的appsecret
wechat.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
@EnableWebSecurity
public 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中使用微信单点登录的详细代码。

暂无评论