通过Spring的RESTful认证通过Spring的RESTful认证(RESTful Authe

2019-05-16 18:00发布

问题:
我们有一个包含敏感信息的基于Spring MVC的REST的API。 该API应该被固定,但是与每个请求发送用户的凭证(用户名/密码组合)是不可取的。 每REST原则(和内部业务需求),服务器必须保持无状态。 该API将通过在混搭风格的方法在另一台服务器消耗。

要求:

  • 客户端发出的请求.../authenticate与证书(无保护的URL); 服务器返回一个包含服务器来验证未来的请求,并保持无状态足够的信息安全令牌。 这可能包括相同的信息Spring Security的记住,我的令牌 。

  • 客户端发出后续请求到各种(被保护)的URL,并附加先前获得的令牌作为查询参数(或不太优选的HTTP请求报头)。

  • 客户不能指望存储cookie。

  • 由于我们使用Spring已经,解决方案应利用春季安全。

我们一直在敲打我的头靠在墙上努力使这项工作,所以希望有人在那里已经解决了这个问题。

鉴于上述情况,你会如何解决这个特定的需求?

Answer 1:

我们成功地得到这个工作完全一样在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 ,如果请求没有在我们的过滤器链认证AuthenticationTokenProcessingFilter

CustomAuthenticationEntryPoint:

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." );
    }
}

AuthenticationTokenProcessingFilter:

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包含一些厕所(和非常特定的病例)码,并且不能被容易地共享。 下面是它的界面:

public interface TokenUtils {
    String getToken(UserDetails userDetails);
    String getToken(UserDetails userDetails, Long expiration);
    boolean validate(String token);
    UserDetails getUserFromToken(String token);
}

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



Answer 2:

你可能会考虑HTTP摘要认证 。 本质上,方案如下:

  1. 请求从客户端进行
  2. 服务器具有独特的随机数串做出响应
  3. 客户端提供用户名和密码(和一些其它值)MD5与随机数散列; 该散列被称为HA1
  4. 服务器就能够验证客户的身份和服务于所要求的材料
  5. 与现时的通信可以继续,直到该服务器提供了一个新的随机数(计数器是用来消除重放攻击)

所有这些通信是通过报头,其中,因为jmort253指出的那样,通常比在url参数传输敏感材料更安全制成。

HTTP摘要认证被支持的Spring Security 。 请注意,虽然文档说,你必须获得客户的明文密码,你可以,如果你有HA1哈希成功地验证了您的客户端。



Answer 3:

关于携带信息的令牌,JSON网络令牌( http://jwt.io )是一个辉煌的技术。 的主要概念是嵌入的信息元素(权利要求)到令牌,然后签署全令牌,以便验证端可以验证该权利要求书的确值得信赖。

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

还有一个弹簧组件(弹簧安全JWT),但我还没有研究什么支持。



Answer 4:

你为什么不开始使用OAuth使用JSON WebTokens

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

OAuth2用户是一个标准化的授权协议/框架。 按照官方的OAuth2 规格 :

你可以找到更多的信息在这里



文章来源: RESTful Authentication via Spring