首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Spring security。如何注销用户(撤销oauth2令牌)

Spring security。如何注销用户(撤销oauth2令牌)
EN

Stack Overflow用户
提问于 2014-02-24 20:19:56
回答 8查看 63.8K关注 0票数 32

当我想要注销时,我调用以下代码:

代码语言:javascript
复制
request.getSession().invalidate();
SecurityContextHolder.getContext().setAuthentication(null);

但在此之后(在使用旧oauth令牌的下一个请求中),我调用

SecurityContextHolder.getContext().getAuthentication();

我在那里看到了我的老用户。

如何修复它?

EN

回答 8

Stack Overflow用户

发布于 2015-09-01 06:26:33

下面是我的实现(Spring OAuth2):

代码语言:javascript
复制
@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);
        }
    }
}

用于测试:

代码语言:javascript
复制
curl -X GET -H "Authorization: Bearer $TOKEN" http://localhost:8080/backend/oauth/revoke-token
票数 43
EN

Stack Overflow用户

发布于 2016-09-27 23:29:20

通过使用Spring OAuth提供的接口,可以改善camposer的响应。实际上,不需要直接访问HTTP头,但可以按如下方式实现移除访问令牌的REST方法:

代码语言:javascript
复制
@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端点。

票数 12
EN

Stack Overflow用户

发布于 2016-12-11 05:29:48

这取决于您正在使用的oauth2“授权类型”的类型。

如果你在客户端应用中使用过spring的@EnableOAuth2Sso,最常见的就是'Authorization Code‘。在这种情况下,Spring security会将登录请求重定向到“Authorization Server”,并使用从“Authorization Server”接收的数据在客户端应用程序中创建一个会话。

你可以很容易地在调用/logout端点的客户端应用程序上销毁你的会话,但是客户端应用程序会再次将用户发送到“授权服务器”,并再次返回logged。

我建议创建一种机制来拦截客户端应用程序的注销请求,并在此服务器代码中调用“授权服务器”来使令牌无效。

我们需要的第一个更改是使用Claudio Tasso建议的代码在授权服务器上创建一个端点,以使用户的access_token无效。

代码语言:javascript
复制
@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

代码语言:javascript
复制
@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上注册

代码语言:javascript
复制
@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令牌,则不能使其无效,因为该令牌不受授权服务器的管理。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21987589

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档