如何在 Spring Security / SpringMVC 中手动设置经过身份验证的用户

新手上路,请多包涵

新用户提交“新帐户”表单后,我想手动登录该用户,这样他们就不必在后续页面上登录。

通过 spring security 拦截器的普通表单登录页面工作得很好。

在新帐户表单控制器中,我正在创建一个 UsernamePasswordAuthenticationToken 并在 SecurityContext 中手动设置它:

 SecurityContextHolder.getContext().setAuthentication(authentication);

在同一页面上,我稍后检查用户是否登录:

 SecurityContextHolder.getContext().getAuthentication().getAuthorities();

这将返回我之前在身份验证中设置的权限。一切都很好。

但是当在我加载的下一个页面上调用相同的代码时,身份验证令牌只是 UserAnonymous。

我不清楚为什么它没有保留我在上一个请求中设置的身份验证。有什么想法吗?

  • 可能与会话 ID 设置不正确有关吗?
  • 是否有可能以某种方式覆盖我的身份验证?
  • 也许我只需要另一个步骤来保存身份验证?
  • 或者我需要做些什么来在整个会话中声明身份验证而不是以某种方式声明单个请求?

只是寻找一些可以帮助我了解这里发生的事情的想法。

原文由 David Parks 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 552
2 个回答

我前段时间遇到了和你一样的问题。我不记得细节了,但下面的代码让事情对我有用。此代码在 Spring Webflow 流中使用,因此在 RequestContext 和 ExternalContext 类中使用。但与您最相关的部分是 doAutoLogin 方法。

 public String registerUser(UserRegistrationFormBean userRegistrationFormBean,
                           RequestContext requestContext,
                           ExternalContext externalContext) {

    try {
        Locale userLocale = requestContext.getExternalContext().getLocale();
        this.userService.createNewUser(userRegistrationFormBean, userLocale, Constants.SYSTEM_USER_ID);
        String emailAddress = userRegistrationFormBean.getChooseEmailAddressFormBean().getEmailAddress();
        String password = userRegistrationFormBean.getChoosePasswordFormBean().getPassword();
        doAutoLogin(emailAddress, password, (HttpServletRequest) externalContext.getNativeRequest());
        return "success";

    } catch (EmailAddressNotUniqueException e) {
        MessageResolver messageResolvable
                = new MessageBuilder().error()
                                      .source(UserRegistrationFormBean.PROPERTYNAME_EMAIL_ADDRESS)
                                      .code("userRegistration.emailAddress.not.unique")
                                      .build();
        requestContext.getMessageContext().addMessage(messageResolvable);
        return "error";
    }

}

private void doAutoLogin(String username, String password, HttpServletRequest request) {

    try {
        // Must be called from request filtered by Spring Security, otherwise SecurityContextHolder is not updated
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
        token.setDetails(new WebAuthenticationDetails(request));
        Authentication authentication = this.authenticationProvider.authenticate(token);
        logger.debug("Logging in with [{}]", authentication.getPrincipal());
        SecurityContextHolder.getContext().setAuthentication(authentication);
    } catch (Exception e) {
        SecurityContextHolder.getContext().setAuthentication(null);
        logger.error("Failure in autoLogin", e);
    }

}

原文由 KevinS 发布,翻译遵循 CC BY-SA 2.5 许可协议

我找不到任何其他完整的解决方案,所以我想我会发布我的。这可能有点 hack,但它解决了上述问题:

 public void login(HttpServletRequest request, String userName, String password)
{

    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(userName, password);

    // Authenticate the user
    Authentication authentication = authenticationManager.authenticate(authRequest);
    SecurityContext securityContext = SecurityContextHolder.getContext();
    securityContext.setAuthentication(authentication);

    // Create a new session and add the security context.
    HttpSession session = request.getSession(true);
    session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);
}

原文由 Stuart McIntyre 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题