访问受 Spring 安全保护的 REST API
Access REST API protected with Spring Security
这是我的配置(使用 Spring Security 3.2.5):
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AuthenticationEntryPoint entryPoint;
@Autowired
private UsernamePasswordAuthenticationFilter userPassAuthFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic()
.authenticationEntryPoint(entryPoint);
http.addFilterAfter(userPassAuthFilter, UsernamePasswordAuthenticationFilter.class)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
这是我的 bean 配置:
@Bean
public AuthenticationManager authenticationManager() {
List providers = new LinkedList();
providers.add(daoAuthenticationProvider());
ProviderManager pm = new ProviderManager(providers);
return pm;
}
@Bean
public AuthenticationEntryPoint entryPoint() {
return new MyAuthenticationEntryPoint();
}
@Bean
public UsernamePasswordAuthenticationFilter restApiAuthenticationFilter() {
MyAuthFilter filter = new MyAuthFilter();
filter.setAuthenticationManager(authenticationManager());
filter.setUsernameParameter("username");
filter.setPasswordParameter("password");
filter.setAuthenticationSuccessHandler(authenticationSuccessHandler());
filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/**"));
return filter;
}
@Bean
public AuthenticationSuccessHandler authenticationSuccessHandler() {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setUseReferer(true);
return successHandler;
}
其中 MyAuthFilter 如下:
public class MyAuthFilter extends UsernamePasswordAuthenticationFilter {
@Transactional
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
//do my job here related to setting some custom header on request.
super.successfulAuthentication(request, response, chain, authResult);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
//check for my header and authenticate if this is the case, otherwise, call super.
return super.attemptAuthentication(request, response);
}
}
而MyAuthenticationEntryPoint如下:
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, org.springframework.security.core.AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
现在,问题是当我访问我手上的一些休息 api 时,我得到如下信息:
curl -i -H "auth_header: a_token_value_here" http://myhost:8080/path/api/list_users
我明白了:
HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
auth_header: a_token_value_here
Location: http://myhost:8080/path/
Content-Length: 0
Date: Thu, 22 Jan 2015 13:01:24 GMT
如您所见,我无法到达请求的 REST API,因为 Spring 不允许我到达那里。在 Spring 检查我是否已通过身份验证后,它只是停止重定向我,而是发送重定向状态响应,如果我访问我会再次得到相同的结果。 谁能指导我如何使用这种方法通过 Spring 安全到 REST API?
您的代码有点混乱,但这里有一些提示:
- 您的配置中有
.httpBasic()
。您是否使用 HTTP Basic 作为身份验证方法?如果没有,请删除。
- 您的身份验证过滤器基于
UsernamePasswordAuthenticationFilter
。那是用于网络浏览器表单身份验证。也许您想将 AbstractAuthenticationProcessingFilter
用作超级 class。
SavedRequestAwareAuthenticationSuccessHandler
用于有状态的、基于会话的登录。这很可能会导致重定向。删除。
这是我的配置(使用 Spring Security 3.2.5):
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AuthenticationEntryPoint entryPoint;
@Autowired
private UsernamePasswordAuthenticationFilter userPassAuthFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic()
.authenticationEntryPoint(entryPoint);
http.addFilterAfter(userPassAuthFilter, UsernamePasswordAuthenticationFilter.class)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
这是我的 bean 配置:
@Bean
public AuthenticationManager authenticationManager() {
List providers = new LinkedList();
providers.add(daoAuthenticationProvider());
ProviderManager pm = new ProviderManager(providers);
return pm;
}
@Bean
public AuthenticationEntryPoint entryPoint() {
return new MyAuthenticationEntryPoint();
}
@Bean
public UsernamePasswordAuthenticationFilter restApiAuthenticationFilter() {
MyAuthFilter filter = new MyAuthFilter();
filter.setAuthenticationManager(authenticationManager());
filter.setUsernameParameter("username");
filter.setPasswordParameter("password");
filter.setAuthenticationSuccessHandler(authenticationSuccessHandler());
filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/**"));
return filter;
}
@Bean
public AuthenticationSuccessHandler authenticationSuccessHandler() {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setUseReferer(true);
return successHandler;
}
其中 MyAuthFilter 如下:
public class MyAuthFilter extends UsernamePasswordAuthenticationFilter {
@Transactional
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
//do my job here related to setting some custom header on request.
super.successfulAuthentication(request, response, chain, authResult);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
//check for my header and authenticate if this is the case, otherwise, call super.
return super.attemptAuthentication(request, response);
}
}
而MyAuthenticationEntryPoint如下:
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, org.springframework.security.core.AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
现在,问题是当我访问我手上的一些休息 api 时,我得到如下信息:
curl -i -H "auth_header: a_token_value_here" http://myhost:8080/path/api/list_users
我明白了:
HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
auth_header: a_token_value_here
Location: http://myhost:8080/path/
Content-Length: 0
Date: Thu, 22 Jan 2015 13:01:24 GMT
如您所见,我无法到达请求的 REST API,因为 Spring 不允许我到达那里。在 Spring 检查我是否已通过身份验证后,它只是停止重定向我,而是发送重定向状态响应,如果我访问我会再次得到相同的结果。 谁能指导我如何使用这种方法通过 Spring 安全到 REST API?
您的代码有点混乱,但这里有一些提示:
- 您的配置中有
.httpBasic()
。您是否使用 HTTP Basic 作为身份验证方法?如果没有,请删除。 - 您的身份验证过滤器基于
UsernamePasswordAuthenticationFilter
。那是用于网络浏览器表单身份验证。也许您想将AbstractAuthenticationProcessingFilter
用作超级 class。 SavedRequestAwareAuthenticationSuccessHandler
用于有状态的、基于会话的登录。这很可能会导致重定向。删除。