当我想要注销时,我调用以下代码:
request.getSession().invalidate();
SecurityContextHolder.getContext().setAuthentication(null);
但在此之后(在使用旧oauth令牌的下一个请求中),我调用
SecurityContextHolder.getContext().getAuthentication();
我在那里看到了我的老用户。
如何修复它?
发布于 2015-09-01 06:26:33
下面是我的实现(Spring OAuth2):
@Controller
public class OAuthController {
@Autowired
private TokenStore tokenStore;
@RequestMapping(value = "/oauth/revoke-token", method = RequestMethod.GET)
@ResponseStatus(HttpStatus.OK)
public void logout(HttpServletRequest request) {
String authHeader = request.getHeader("Authorization");
if (authHeader != null) {
String tokenValue = authHeader.replace("Bearer", "").trim();
OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
tokenStore.removeAccessToken(accessToken);
}
}
}
用于测试:
curl -X GET -H "Authorization: Bearer $TOKEN" http://localhost:8080/backend/oauth/revoke-token
发布于 2016-09-27 23:29:20
通过使用Spring OAuth提供的接口,可以改善camposer的响应。实际上,不需要直接访问HTTP头,但可以按如下方式实现移除访问令牌的REST方法:
@Autowired
private AuthorizationServerTokenServices authorizationServerTokenServices;
@Autowired
private ConsumerTokenServices consumerTokenServices;
@RequestMapping("/uaa/logout")
public void logout(Principal principal, HttpServletRequest request, HttpServletResponse response) throws IOException {
OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) principal;
OAuth2AccessToken accessToken = authorizationServerTokenServices.getAccessToken(oAuth2Authentication);
consumerTokenServices.revokeToken(accessToken.getValue());
String redirectUrl = getLocalContextPathUrl(request)+"/logout?myRedirect="+getRefererUrl(request);
log.debug("Redirect URL: {}",redirectUrl);
response.sendRedirect(redirectUrl);
return;
}
我还添加了到Spring Security注销过滤器端点的重定向,因此会话无效,客户端必须再次提供凭据才能访问/oauth/authorize端点。
发布于 2016-12-11 05:29:48
这取决于您正在使用的oauth2“授权类型”的类型。
如果你在客户端应用中使用过spring的@EnableOAuth2Sso
,最常见的就是'Authorization Code‘。在这种情况下,Spring security会将登录请求重定向到“Authorization Server”,并使用从“Authorization Server”接收的数据在客户端应用程序中创建一个会话。
你可以很容易地在调用/logout
端点的客户端应用程序上销毁你的会话,但是客户端应用程序会再次将用户发送到“授权服务器”,并再次返回logged。
我建议创建一种机制来拦截客户端应用程序的注销请求,并在此服务器代码中调用“授权服务器”来使令牌无效。
我们需要的第一个更改是使用Claudio Tasso建议的代码在授权服务器上创建一个端点,以使用户的access_token无效。
@Controller
@Slf4j
public class InvalidateTokenController {
@Autowired
private ConsumerTokenServices consumerTokenServices;
@RequestMapping(value="/invalidateToken", method= RequestMethod.POST)
@ResponseBody
public Map<String, String> logout(@RequestParam(name = "access_token") String accessToken) {
LOGGER.debug("Invalidating token {}", accessToken);
consumerTokenServices.revokeToken(accessToken);
Map<String, String> ret = new HashMap<>();
ret.put("access_token", accessToken);
return ret;
}
}
然后在客户端应用程序中创建一个LogoutHandler
@Slf4j
@Component
@Qualifier("mySsoLogoutHandler")
public class MySsoLogoutHandler implements LogoutHandler {
@Value("${my.oauth.server.schema}://${my.oauth.server.host}:${my.oauth.server.port}/oauth2AuthorizationServer/invalidateToken")
String logoutUrl;
@Override
public void logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) {
LOGGER.debug("executing MySsoLogoutHandler.logout");
Object details = authentication.getDetails();
if (details.getClass().isAssignableFrom(OAuth2AuthenticationDetails.class)) {
String accessToken = ((OAuth2AuthenticationDetails)details).getTokenValue();
LOGGER.debug("token: {}",accessToken);
RestTemplate restTemplate = new RestTemplate();
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("access_token", accessToken);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "bearer " + accessToken);
HttpEntity<String> request = new HttpEntity(params, headers);
HttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter();
HttpMessageConverter stringHttpMessageConverternew = new StringHttpMessageConverter();
restTemplate.setMessageConverters(Arrays.asList(new HttpMessageConverter[]{formHttpMessageConverter, stringHttpMessageConverternew}));
try {
ResponseEntity<String> response = restTemplate.exchange(logoutUrl, HttpMethod.POST, request, String.class);
} catch(HttpClientErrorException e) {
LOGGER.error("HttpClientErrorException invalidating token with SSO authorization server. response.status code: {}, server URL: {}", e.getStatusCode(), logoutUrl);
}
}
}
}
并在WebSecurityConfigurerAdapter
上注册
@Autowired
MySsoLogoutHandler mySsoLogoutHandler;
@Override
public void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.logout()
.logoutSuccessUrl("/")
// using this antmatcher allows /logout from GET without csrf as indicated in
// https://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html#csrf-logout
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
// this LogoutHandler invalidate user token from SSO
.addLogoutHandler(mySsoLogoutHandler)
.and()
...
// @formatter:on
}
注意:如果您使用的是JWT web令牌,则不能使其无效,因为该令牌不受授权服务器的管理。
https://stackoverflow.com/questions/21987589
复制相似问题