Spring Security-基于令牌的API身份验证和用户/密码身份验证
问题内容:
我试图创建一个主要使用Spring提供REST API的webapp,并试图配置安全性。
我正在尝试实现这种模式:https :
//developers.google.com/accounts/docs/MobileApps(Google完全更改了该页面,因此不再有意义-
请参阅我在此引用的页面:http:
//web.archive.org/web/20130822184827/https://developers.google.com/accounts/docs/MobileApps)
这是我需要完成的:
- Web应用程序具有简单的登录/注册表单,可用于普通的spring用户/密码身份验证(之前使用dao / authenticationmanager / userdetailsservice等完成了此类操作)
- REST API端点是无状态会话,并且每个请求都基于请求所提供的令牌进行身份验证
(例如,用户使用常规形式登录/注册,webapp提供带有令牌的安全cookie,然后可在以下API请求中使用该令牌)
我有一个正常的身份验证设置,如下所示:
@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();
}
我当时正在考虑添加一个预身份验证过滤器,该过滤器会检查请求中的令牌,然后设置安全上下文(这是否意味着将跳过正常的后续身份验证?),但是,我所拥有的权限超出了普通用户/密码基于令牌的安全性并没有做太多,但是基于其他一些示例,我想到了以下内容:
安全配置:
@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();
}
我的自定义休息过滤器:
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_auth过滤器是执行此操作的最佳方法吗?
编辑
我写下了发现的内容以及如何使用Spring-security(包括代码)来实现标准令牌实现(不是OAuth)
希望对其他人有所帮助。
问题答案:
我相信您提到的错误仅是因为AbstractAuthenticationProcessingFilter
您使用的基类需要一个AuthenticationManager
。如果您不打算使用它,可以将其设置为无操作,也可以Filter
直接实现。如果您Filter
可以验证请求并进行设置,SecurityContext
则通常将跳过下游处理(这取决于下游过滤器的实现,但我在您的应用程序中看不到任何奇怪的东西,因此它们的行为可能都如此)。
如果您是我,我可能会考虑将API端点放在一个完全独立的过滤器链(另一个WebSecurityConfigurerAdapter
bean)中。但这只会使事情更容易阅读,而不一定至关重要。
您可能会发现(如评论中的建议)最终重新发明了轮子,但是尝试无害,并且您可能会在此过程中学习更多有关Spring和Security的知识。
补充:github方法非常有趣:用户只需在基本身份验证中使用令牌作为密码,服务器就不需要自定义过滤器(BasicAuthenticationFilter
很好)。