我正在学习 Spring-boot 和 Oauth2。我有几个问题。
我正在实施针对 CSRF 的保护
.csrf()
.requireCsrfProtectionMatcher(new AndRequestMatcher(
new NegatedRequestMatcher(new AntPathRequestMatcher("/test", HttpMethod.OPTIONS.toString()))
));
这工作正常,但是当我尝试访问我的 API 上的另一个路径时,我收到了这条消息。
"error": "access_denied"
"error_description": "Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'."
我尝试在我的请求中使用 JSESSIONID 设置 cookie,但没有成功
Status
403 Prohibido Show explanation Loading time: 22
Request headers
Accept: application/json
Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36
Authorization: Bearer 4abe8cbc-a528-4d52-8e20-a0aa198056d2
Content-Type: application/json
DNT: 1
Accept-Encoding: gzip, deflate
Accept-Language: es-ES,es;q=0.8,en;q=0.6,und;q=0.4
Cookie: JSESSIONID=3DB726CA18F6628719703891B7DCA0A2
Response headers
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
Cache-Control: no-store
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 05 Jan 2016 03:59:45 GMT
我也尝试在我的项目上设置我的 CSRF 过滤器,最糟糕的是,这并没有让我得到带有 JSESSIONID 的 Cookie。字面上什么都不做
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
CustomAuthenticationProvider customAuthenticationProvider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests()
.antMatchers("/test").permitAll().anyRequest()
.authenticated()
.and().csrf()
.csrfTokenRepository(csrfTokenRepository()).and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
}
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null
&& !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
};
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
}
知道我做错了什么吗?
编辑我找到了我认为的部分解决方案,但现在我有几个问题。
解决方案:
使我的 CrsfTokenRepository 成为@Bean
@Bean
public CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
只为我做了一堂课CsrfHeaderFilter
public class CsrfHeaderFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
}
并将我的配置WebSecurityConfiguration
移到我的Oauth2Configuration
@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Autowired
private CustomLogoutSuccessHandler customLogoutSuccessHandler;
@Autowired
private CsrfTokenRepository csrfTokenRepository;
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources
.resourceId(RESOURCE_ID);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
// Logout
.logout()
.logoutUrl("/oauth/logout")
.logoutSuccessHandler(customLogoutSuccessHandler)
.and()
//Session management
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
//URI's to verify
.authorizeRequests()
.antMatchers("/test").hasRole("ADMIN")
.antMatchers("/users").authenticated()
.antMatchers("/**").authenticated()
.antMatchers("/productos").hasAnyRole("ADMIN, VENDEDOR")
.and()
.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class)
.csrf()
.csrfTokenRepository(csrfTokenRepository);
}
}
我的问题是:
- 这个解决方案好吗?是个好习惯吗?
- JSESSIONID 和 XSRF-Token 不需要附加在我的 angularjs 请求中吗?