当前位置: 首页 > 知识库问答 >
问题:

Spring SecurityOAuth2-验证后使会话无效

严兴言
2023-03-14

我们正在使用Spring安全OAuth2保护REST服务。应用程序可以调用/oauth/授权/oauth/令牌/rest-api终结点。令牌和rest api终结点是无状态的,不需要会话。

我们可以在用户经过身份验证后使会话无效吗?如果是,最好的方法是什么。我们希望用户在调用/oauth/authorize时始终登录。当前,每当会话存在时,对/oauth/authorize的调用都会跳过身份验证。

共有3个答案

高溪叠
2023-03-14

第一:在您的配置中,为oauth声明带有令牌存储的bean

@Bean
@Primary
public TokenStore tokenStore() {
    return new InMemoryTokenStore();
}

对于控制器方法,我们制作了以下类

@Controller
 public class TokenController {

    @RequestMapping(value = "/oauth/token/revoke", method = RequestMethod.POST)
    public @ResponseBody void create(@RequestParam("token") String value) {
        this.revokeToken(value);
    }

    @Autowired
    TokenStore tokenStore;

    public boolean revokeToken(String tokenValue) {
        OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
        if (accessToken == null) {
            return false;
        }
        if (accessToken.getRefreshToken() != null) {
            tokenStore.removeRefreshToken(accessToken.getRefreshToken());
        }
        tokenStore.removeAccessToken(accessToken);
        return true;
    }
}

如果您不想使用这种方法,您可以获取当前用户的令牌自动连线主体

    OAuth2Authentication authorization = (OAuth2Authentication) principal;
    OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authorization.getDetails();
    String token = details.getTokenValue();

或者甚至自动连接OAuth2身份验证

    OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
    String token = details.getTokenValue();

胡俊贤
2023-03-14

据我所知,您正在尝试在执行某些操作后以编程方式注销。也许您应该研究一下SecurityContextLogoutHandler,看看它是如何工作的。这里有一个注销的方法。我认为把它作为一个建议会解决你的问题。

public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
      Assert.notNull(request, "HttpServletRequest required");
      if (invalidateHttpSession) {
          HttpSession session = request.getSession(false);
          if (session != null) {
              session.invalidate();
          }
      }

      SecurityContextHolder.clearContext();
  }
仲浩旷
2023-03-14

理解到这个问题有点老了,我希望下面的内容能对那些为这个问题寻找正确答案的人有所帮助

OP询问的不是令牌失效,而是如何在用户身份验证成功通过并将有效的access_token或authorization_code(用于后续获取access_token)返回给客户端后立即在Spring OAuth2服务器上使http会话失效。

这个用例仍然没有现成的解决方案。但是SpringSecurityOAuth最活跃的贡献者DaveSyer的工作方法可以在GitHub上找到

只需从那里复制代码:

@Service
@Aspect
public class SessionInvalidationOauth2GrantAspect {

    private static final String FORWARD_OAUTH_CONFIRM_ACCESS = "forward:/oauth/confirm_access";
    private static final Logger logger = Logger.getLogger(SessionInvalidationOauth2GrantAspect.class);

    @AfterReturning(value = "within(org.springframework.security.oauth2.provider.endpoint..*) && @annotation(org.springframework.web.bind.annotation.RequestMapping)", returning = "result")
    public void authorizationAdvice(JoinPoint joinpoint, ModelAndView result) throws Throwable {

        // If we're not going to the confirm_access page, it means approval has been skipped due to existing access
        // token or something else and they'll be being sent back to app. Time to end session.
        if (!FORWARD_OAUTH_CONFIRM_ACCESS.equals(result.getViewName())) {
            invalidateSession();
        }
    }

    @AfterReturning(value = "within(org.springframework.security.oauth2.provider.endpoint..*) && @annotation(org.springframework.web.bind.annotation.RequestMapping)", returning = "result")
    public void authorizationAdvice(JoinPoint joinpoint, View result) throws Throwable {
        // Anything returning a view and not a ModelView is going to be redirecting outside of the app (I think). 
        // This happens after the authorize approve / deny page with the POST to /oauth/authorize. This is the time
        // to kill the session since they'll be being sent back to the requesting app.
        invalidateSession();
    }

    @AfterThrowing(value = "within(org.springframework.security.oauth2.provider.endpoint..*) &&  @annotation(org.springframework.web.bind.annotation.RequestMapping)", throwing = "error")
    public void authorizationErrorAdvice(JoinPoint joinpoint) throws Throwable {
        invalidateSession();
    }

    private void invalidateSession() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                .getRequest();
        HttpSession session = request.getSession(false);
        if (session != null) {
            logger.warn(String.format("As part of OAuth application grant processing, invalidating session for request %s", request.getRequestURI()));

            session.invalidate();
            SecurityContextHolder.clearContext();
        }
    }

}

添加pom。xml

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
</dependency>

另一个解决方案是将会话超时设置为某个非常小的值。实现这一点的最简单方法是应用以下内容。yml配置:

server:
  session:
    timeout: 1

但这并不是理想的解决方案,因为提供程序可以使用的最小值是1(为无限个会话保留零),并且是以分钟而不是秒为单位

 类似资料:
  • 我正在构建一个API,并试图在多个上下文中解决身份验证问题。 API需要为我们创建和部署的客户端应用程序提供服务,并使用密码处理经过身份验证的请求。在每个请求中都发送密码并不是一个好主意,因此首先点击登录endpoint并获得会话ID更有意义。问题中的webapp是用AngularJS编写的,应该在localStorage中跟踪自己的会话,以减轻会话劫持并消除对cookie的依赖以跟踪会话。 we

  • 在身份验证等情况下,与会话相比,使用JWTs有什么优势? 它是作为独立方法使用还是在会话中使用?

  • 在我的Vaadin应用程序中,当Vaadin在“session Timeout”消息之后没有使会话无效时,我遇到了一个问题。收到此消息后,用户有时可以单击链接或刷新页面,并继续工作,就像他们仍在登录一样。我使用以下参数: Last参数(session-timeout)也在context.xml(session-timeout=900)和web.xml(session-config/session-

  • null 一些重要注意事项: 我们有传输安全性(HTTPS及其最好的朋友); 在窗帘后面,web应用程序代表当前用户将大量操作委托给外部服务(这些系统确实将Bob识别为其用户之一)--这意味着我们必须将Bob的凭据转发给它们。 现在,我们如何(在每个请求上)对Bob进行身份验证?哪一种方法会是实施这样的事情的合理方法呢? null null 非常感谢您花时间阅读以下内容:)

  • 在成功登录Laravel后,我尝试在会话中输入一些值,例如name、img、username、last_Login等。我尝试使用Auth::user()在回显时从用户详细信息中获取每个详细信息。 当用户成功登录时,如何立即从不同的表中放入其他参数 我的LoginController.php

  • 我的web应用程序的当前架构有一个网关服务器,它组织了一系列微服务,授权发生在网关,如果给定的原则被认证,它们可以与一些下游服务对话。 下游服务获取所需的数据,以标识给定的经过身份验证的客户端。然而,Spring证券违约行为开始出现,并引发了预期的: 假定我可以在任何给定的微服务中使用会话id和+XSRF令牌来验证用户是否经过身份验证,并知道哪个用户登录了(我目前使用的是Http Basic)。