我从上面的好答案开始(
https://dev59.com/nVwY5IYBdhLWcg3wsplj#33963286),但是在我的 Spring Security 版本(4.2.8.RELEASE)中失败了。原因是在
org.springframework.security.access.intercept.AbstractSecurityInterceptor#authenticateIfRequired
中,答案中的
PreAuthenticatedAuthenticationToken
没有被认证。必须传递一些 GrantedAuthorities。
此外,在 URL 参数中共享令牌并不好,它应该始终隐藏在 HTTPs 负载或标头中。代替地,加载 HTML 模板并将令牌值插入到
${token}
占位符字段中。
这里是修订版:
注意:使用的
UserDetails
实现了
org.springframework.security.core.userdetails.UserDetails
。
@Component
public class SocialAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Autowired
private OAuth2TokenStore tokenStore;
@Qualifier("tokenServices")
@Autowired
private AuthorizationServerTokenServices authTokenServices;
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
IClient user = ((SocialUserDetails) authentication.getPrincipal()).getUser();
if (user instanceof IRegistration) {
response.sendRedirect(subscriberRegistrationUrl + "/" + user.getId());
}
OAuth2AccessToken token = loginUser(user);
String html = IOUtils.toString(getClass().getResourceAsStream("/html/socialLoginRedirect.html"));
html = html.replace("${token}", token.getValue());
response.getOutputStream().write(html.getBytes(StandardCharsets.UTF_8));
}
private OAuth2Authentication convertAuthentication(Authentication authentication) {
OAuth2Request request = new OAuth2Request(null, authentication.getName(),
authentication.getAuthorities(), true, null,
null, null, null, null);
return new OAuth2Authentication(request,
new PreAuthenticatedAuthenticationToken(authentication.getPrincipal(), "N/A", authentication.getAuthorities())
);
}
public OAuth2AccessToken loginUser(IClient user) {
SecurityContext securityContext = SecurityContextHolder.getContext();
UserDetails userDetails = new UserDetails(user);
Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, "N/A", userDetails.getAuthorities());
securityContext.setAuthentication(authentication);
OAuth2Authentication oAuth2Authentication = convertAuthentication(authentication);
tokenStore.deleteTokensForUserId(user.getUsername());
OAuth2AccessToken oAuth2AccessToken = authTokenServices.createAccessToken(oAuth2Authentication);
((DefaultOAuth2AccessToken) oAuth2AccessToken).setAdditionalInformation(new HashMap<>());
oAuth2AccessToken.getAdditionalInformation().put("userId", user.getId());
return oAuth2AccessToken;
}
}
示例 socialLoginRedirect.html
:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Example App</title>
<meta http-equiv="Refresh" content="0; url=/index.html#/home"/>
</head>
<script>
window.sessionStorage.setItem('access_token', '${token}');
</script>
<body>
<p>Please follow <a href="/index.html#/home">this link</a>.</p>
</body>
</html>
在
WebSecurityConfigurerAdapter
中的配置连线:
@Configuration
@EnableWebSecurity
@EnableWebMvc
@Import(WebServiceConfig.class)
public class AuthenticationConfig extends WebSecurityConfigurerAdapter {
@Value("${registrationUrl}")
private String registrationUrl;
@Autowired
private SocialAuthenticationSuccessHandler socialAuthenticationSuccessHandler;
@Value("${loginUrl}")
private String loginUrl;
@Override
protected void configure(HttpSecurity http) throws Exception {
List<String> permitAllUrls = new ArrayList<>();
permitAllUrls.add("/auth/**");
http.authorizeRequests().antMatchers(permitAllUrls.toArray(new String[0])).permitAll();
SpringSocialConfigurer springSocialConfigurer = new SpringSocialConfigurer();
springSocialConfigurer.signupUrl(registrationUrl);
springSocialConfigurer.postFailureUrl(loginUrl);
springSocialConfigurer
.addObjectPostProcessor(new ObjectPostProcessor<SocialAuthenticationFilter>() {
@SuppressWarnings("unchecked")
public SocialAuthenticationFilter postProcess(SocialAuthenticationFilter filter){
filter.setAuthenticationSuccessHandler(socialAuthenticationSuccessHandler);
return filter;
}
});
http.apply(springSocialConfigurer);
http.logout().disable().csrf().disable();
http.requiresChannel().anyRequest().requiresSecure();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}