Spring Security – 基于令牌的APIauthentication和用户/密码authentication

我正在尝试创build一个Web应用程序,主要是使用Spring提供一个REST API,并试图configuration安全方面。

我试图实现这种模式: https : //developers.google.com/accounts/docs/MobileApps (谷歌已经完全改变了这个页面,所以不再有意义 – 请参阅我在这里指的页面: http: //web.archive.org/web/20130822184827/https://developers.google.com/accounts/docs/MobileApps )

这是我需要实现的:

  • Web应用程序具有简单的login/registry单,可以和普通的spring用户/密码authentication一起工作(之前用dao / authenticationmanager / userdetailsservice等做过这种types的事情)
  • REST API端点是无状态会话,并且每个请求都是基于随请求提供的令牌进行身份validation的

(例如,用户使用常规表单login/注册,webapp提供安全的cookie和令牌,然后可以在以下API请求中使用)

我有一个正常的身份validation设置如下:

@Override protected void configure(HttpSecurity http) throws Exception { http .csrf() .disable() .authorizeRequests() .antMatchers("/resources/**").permitAll() .antMatchers("/mobile/app/sign-up").permitAll() .antMatchers("/v1/**").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/") .loginProcessingUrl("/loginprocess") .failureUrl("/?loginFailure=true") .permitAll(); } 

我正在考虑添加一个pre-authfilter,检查请求中的令牌,然后设置安全上下文(这意味着正常的后续authentication将被跳过?),但是,超出正常的用户/密码我有基于令牌的安全性并没有做太多的事情,但是基于其他一些例子,我提出了以下内容:

安全configuration:

 @Override protected void configure(HttpSecurity http) throws Exception { http .csrf() .disable() .addFilter(restAuthenticationFilter()) .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() .exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint()).and() .antMatcher("/v1/**") .authorizeRequests() .antMatchers("/resources/**").permitAll() .antMatchers("/mobile/app/sign-up").permitAll() .antMatchers("/v1/**").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/") .loginProcessingUrl("/loginprocess") .failureUrl("/?loginFailure=true") .permitAll(); } 

我的自定义restfilter

 public class RestAuthenticationFilter extends AbstractAuthenticationProcessingFilter { public RestAuthenticationFilter(String defaultFilterProcessesUrl) { super(defaultFilterProcessesUrl); } private final String HEADER_SECURITY_TOKEN = "X-Token"; private String token = ""; @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; this.token = request.getHeader(HEADER_SECURITY_TOKEN); //If we have already applied this filter - not sure how that would happen? - then just continue chain if (request.getAttribute(FILTER_APPLIED) != null) { chain.doFilter(request, response); return; } //Now mark request as completing this filter request.setAttribute(FILTER_APPLIED, Boolean.TRUE); //Attempt to authenticate Authentication authResult; authResult = attemptAuthentication(request, response); if (authResult == null) { unsuccessfulAuthentication(request, response, new LockedException("Forbidden")); } else { successfulAuthentication(request, response, chain, authResult); } } /** * Attempt to authenticate request - basically just pass over to another method to authenticate request headers */ @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { AbstractAuthenticationToken userAuthenticationToken = authUserByToken(); if(userAuthenticationToken == null) throw new AuthenticationServiceException(MessageFormat.format("Error | {0}", "Bad Token")); return userAuthenticationToken; } /** * authenticate the user based on token, mobile app secret & user agent * @return */ private AbstractAuthenticationToken authUserByToken() { AbstractAuthenticationToken authToken = null; try { // TODO - just return null - always fail auth just to test spring setup ok return null; } catch (Exception e) { logger.error("Authenticate user by token error: ", e); } return authToken; } 

上面实际上导致应用程序启动时出现错误: authenticationManager must be specified任何人都可以告诉我如何做到这一点 – pre_authfilter是最好的方法吗?


编辑

我写了我发现了什么,以及如何使用Spring-security(包括代码)实现标准令牌实现(而不是OAuth)

问题和方法/解决scheme的概述

用Spring-security实现解决scheme

希望它可以帮助其他人..

我相信你提到的错误只是因为你使用的AbstractAuthenticationProcessingFilter基类需要一个AuthenticationManager 。 如果你不打算使用它,你可以将它设置为no-op,或者直接实现Filter 。 如果您的Filter可以validation请求并设置SecurityContext那么通常下游处理将被跳过(这取决于下游filter的实现,但是在您的应用程序中我没有看到任何奇怪的东西,所以它们可能都performance得如此)。

如果我是你,我可能会考虑将API端点放在一个完全独立的过滤链(另一个WebSecurityConfigurerAdapter bean)中。 但是,这只会让事情变得更容易阅读,而不一定是至关重要

您可能会发现(正如评论中所build议的那样)您最终重新发明了方向盘,但在尝试中没有任何伤害,您可能会在此过程中学习更多有关Spring和Security的知识。

附加: github方法非常有趣:用户只需在基本auth中使用token作为密码,服务器不需要自定义filter( BasicAuthenticationFilter很好)。