通过Spring进行RESTful身份验证

时间:2012-05-31 01:16:17

标签: java rest spring-mvc spring-security

问题:
我们有一个基于Spring MVC的RESTful API,它包含敏感信息。应该保护API,但是不希望向每个请求发送用户的凭证(用户/通过组合)。根据REST准则(和内部业务要求),服务器必须保持无状态。该API将由mashup风格的方法由另一台服务器使用。

要求:

  • 客户端使用凭据向.../authenticate(未受保护的URL)发出请求;服务器返回一个安全令牌,其中包含足够的信息,供服务器验证将来的请求并保持无状态。这可能包含与Spring Security的Remember-Me Token相同的信息。

  • 客户端对各种(受保护的)URL进行后续请求,将先前获取的令牌附加为查询参数(或者,不太希望的是HTTP请求头)。

  • 不能指望客户存储Cookie。

  • 由于我们已经使用Spring,因此该解决方案应该使用Spring Security。

我们一直在试图让这项工作碰壁,所以希望那里的人已经解决了这个问题。

鉴于上述情况,您如何解决这一特殊需求?

4 个答案:

答案 0 :(得分:177)

我们设法完全按照OP中的描述使其工作,并希望其他人可以使用该解决方案。这就是我们所做的:

设置安全上下文,如下所示:

<security:http realm="Protected API" use-expressions="true" auto-config="false" create-session="stateless" entry-point-ref="CustomAuthenticationEntryPoint">
    <security:custom-filter ref="authenticationTokenProcessingFilter" position="FORM_LOGIN_FILTER" />
    <security:intercept-url pattern="/authenticate" access="permitAll"/>
    <security:intercept-url pattern="/**" access="isAuthenticated()" />
</security:http>

<bean id="CustomAuthenticationEntryPoint"
    class="com.demo.api.support.spring.CustomAuthenticationEntryPoint" />

<bean id="authenticationTokenProcessingFilter"
    class="com.demo.api.support.spring.AuthenticationTokenProcessingFilter" >
    <constructor-arg ref="authenticationManager" />
</bean>

正如您所看到的,我们已经创建了一个自定义AuthenticationEntryPoint,如果我们的401 Unauthorized未在过滤器链中对请求进行身份验证,则基本上只返回{​​{1}}。 / p>

<强> CustomAuthenticationEntryPoint

AuthenticationTokenProcessingFilter

<强> AuthenticationTokenProcessingFilter

public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException authException) throws IOException, ServletException {
        response.sendError( HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized: Authentication token was either missing or invalid." );
    }
}

显然, public class AuthenticationTokenProcessingFilter extends GenericFilterBean { @Autowired UserService userService; @Autowired TokenUtils tokenUtils; AuthenticationManager authManager; public AuthenticationTokenProcessingFilter(AuthenticationManager authManager) { this.authManager = authManager; } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { @SuppressWarnings("unchecked") Map<String, String[]> parms = request.getParameterMap(); if(parms.containsKey("token")) { String token = parms.get("token")[0]; // grab the first "token" parameter // validate the token if (tokenUtils.validate(token)) { // determine the user based on the (already validated) token UserDetails userDetails = tokenUtils.getUserFromToken(token); // build an Authentication object with the user's info UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails((HttpServletRequest) request)); // set the authentication into the SecurityContext SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(authentication)); } } // continue thru the filter chain chain.doFilter(request, response); } } 包含一些私有(并且特定于案例的)代码,无法轻易共享。这是它的界面:

TokenUtils

这应该让你有一个良好的开端。快乐的编码。 :)

答案 1 :(得分:22)

您可以考虑Digest Access Authentication。基本上协议如下:

  1. 请求来自客户
  2. 服务器使用唯一的随机数字字符串
  3. 进行响应
  4. 客户端提供用户名和密码(以及其他一些值)md5与nonce进行哈希处理;此哈希称为HA1
  5. 然后,服务器可以验证客户的身份并提供所需的材料
  6. 与nonce的通信可以继续,直到服务器提供新的nonce(计数器用于消除重放攻击)
  7. 所有这些通信都是通过标头进行的,正如jmort253所指出的那样,它通常比在url参数中传递敏感材料更安全。

    Spring Security支持摘要访问身份验证。请注意,虽然文档说您必须能够访问客户端的纯文本密码,但您可以为您的客户successfully authenticate if you have the HA1 hash

答案 2 :(得分:4)

关于携带信息的令牌,JSON Web令牌(http://jwt.io)是一项出色的技术。主要概念是将信息元素(声明)嵌入到令牌中,然后对整个令牌进行签名,以便验证端可以验证声明确实值得信任。

我使用这个Java实现:https://bitbucket.org/b_c/jose4j/wiki/Home

还有一个Spring模块(spring-security-jwt),但我没有研究它支持的内容。

答案 3 :(得分:1)

为什么不开始使用带有JSON WebTokens的OAuth

http://projects.spring.io/spring-security-oauth/

OAuth2是标准化的授权协议/框架。根据官方OAuth2 Specification

您可以找到更多信息here