如何使用 Spring-security 以编程方式登录用户?

Posted

技术标签:

【中文标题】如何使用 Spring-security 以编程方式登录用户?【英文标题】:How to login a user programmatically using Spring-security? 【发布时间】:2014-10-15 21:31:49 【问题描述】:

我需要以编程方式登录通过 Facebook API 进行身份验证的用户。原因是每个用户(例如购物车)关联了许多项目,因此一旦用户使用 Facebook API 进行身份验证,我还需要使用 spring security 登录用户才能访问他/她的购物车。

根据我的研究,有很多方法可以实现它,但我无法部署其中任何一个,因为我正在从我的代码发送登录请求,另一个问题是有些人创建了用户对象但他们没有解释如何创建它。

那些创建了用户对象但没有解释如何的人。

来自第一个例子:this answer

  Authentication auth = 
  new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());

来自第二个例子:this one

  34.User details = new User(username);
  35.token.setDetails(details);

来自第三个例子:this one

  Authentication authentication = new UsernamePasswordAuthenticationToken(user, null,
  AuthorityUtils.createAuthorityList("ROLE_USER"));

另一个example is here,它没有帮助,因为我需要从我自己的代码而不是浏览器登录用户;因此我不知道如何填充 HttpServletRequest 对象。

protected void automatedLogin(String username, String password, HttpServletRequest request) 

我的代码

...
if(isAuthenticatedByFB())

    login(username);
    return "success";

else
    return "failed";

【问题讨论】:

【参考方案1】:

不幸的是,Spring 安全中似乎没有“完全”支持编程登录。以下是我成功完成的方法:

@Autowired AuthenticationSuccessHandler successHandler;
@Autowired AuthenticationManager authenticationManager;  
@Autowired AuthenticationFailureHandler failureHandler;

public void login(HttpServletRequest request, HttpServletResponse response, String username, String password) 
    UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
    token.setDetails(new WebAuthenticationDetails(request));//if request is needed during authentication
    Authentication auth;
    try 
        auth = authenticationManager.authenticate(token);
     catch (AuthenticationException e) 
        //if failureHandler exists  
        try 
            failureHandler.onAuthenticationFailure(request, response, e);
         catch (IOException | ServletException se) 
            //ignore
        
        throw e;
    
    SecurityContext securityContext = SecurityContextHolder.getContext();
    securityContext.setAuthentication(auth);
    successHandler.onAuthenticationSuccess(request, response, auth);//if successHandler exists  
    //if user has a http session you need to save context in session for subsequent requests
    HttpSession session = request.getSession(true);
    session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);

更新 Spring的RememberMeAuthenticationFilter.doFilter()基本相同

【讨论】:

谢谢,请您进一步详细说明。我需要任何 requestHandler 吗?如何配置项目? 我使用典型的 spring 安全配置,它像往常一样用于处理 HTTP 请求。当我需要在内部对用户进行身份验证时,上面的代码在特殊情况下有效。 如何使用 oauth 2.0 进行身份验证? 请问,您在哪里/如何定义提供给session.setAttribute(...)securityContext 变量? @JayEdwards 感谢您的提问,我修复了代码 sn-p【参考方案2】:

此代码来自Grails' Spring Security Core -Plugin,它是在 Apache 2.0 许可下发布的。我添加了导入只是为了指出确切的类型。原作者是伯特·贝克威斯。

import org.springframework.security.core.userdetails.UserCache;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

...

public static void reauthenticate(final String username, final String password) 
    UserDetailsService userDetailsService = getBean("userDetailsService");
    UserCache userCache = getBean("userCache");

    UserDetails userDetails = userDetailsService.loadUserByUsername(username);
    SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(
            userDetails, password == null ? userDetails.getPassword() : password, userDetails.getAuthorities()));
    userCache.removeUserFromCache(username);

getBean 方法仅提供来自应用程序上下文的 bean。

【讨论】:

所以这实际上验证了所有密码都是真实的,甚至是 badones。

以上是关于如何使用 Spring-security 以编程方式登录用户?的主要内容,如果未能解决你的问题,请参考以下文章

如何禁用 spring-security 登录屏幕?

spring-security saml2:如何获取当前用户?

Spring-Security:升级到 Spring-Security 4.1 后,用户名发送为空以进行登录

如何使用 spring-security 设置 JerseyTest?

如何以编程方式添加 servlet 过滤器?

如何使用spring-security通过用户名和密码登录?