Spring Security Jwt 令牌在从 Angular 请求表单时允许所有 Options 方法
我不知道出了什么问题,我在网上到处查了,似乎和我拥有的情况一样,但我遇到了这个问题:
我正在使用 Angular 的 HttpClient 并通过 Angular 拦截器设置 Header,因为我的 Java Rest API 使用 JWT 进行身份验证,需要在 Header 中包含 token,这样它才能获取并验证用户请求,但是 Angular 拦截器工作不正常。我在 Java 端获取的 token 为 null,并且出现错误。请帮我解决这个问题。
最后我发现这可能是 Spring Security 的问题,因为我调试时发现 OPTIONS 请求经过了所有过滤器,但它没有头,所以会显示 token 并抛出异常。如果 OPTIONS 方法请求被绕过并允许,那么我的问题可能就能解决
Spring Boot 安全配置
package com.techprimers.security.jwtsecurity.config;
import com.techprimers.security.jwtsecurity.security.JwtAuthenticationEntryPoint;
import com.techprimers.security.jwtsecurity.security.JwtAuthenticationProvider;
import com.techprimers.security.jwtsecurity.security.JwtAuthenticationTokenFilter;
import com.techprimers.security.jwtsecurity.security.JwtSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import java.util.Collections;
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@Configuration
public class JwtSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationProvider authenticationProvider;
@Autowired
private JwtAuthenticationEntryPoint entryPoint;
@Bean
public AuthenticationManager authenticationManager() {
return new ProviderManager(Collections.singletonList(authenticationProvider));
}
@Bean
public JwtAuthenticationTokenFilter authenticationTokenFilter() {
JwtAuthenticationTokenFilter filter = new JwtAuthenticationTokenFilter();
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationSuccessHandler(new JwtSuccessHandler());
return filter;
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests().antMatchers("**/rest/**").authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(entryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(authenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
http.headers().cacheControl();
}
}
Angular 拦截器代码
import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// add authorization header with jwt token if available
console.log("i am inside");
request = request.clone({
setHeaders: {
Accept: 'application/json',
Authorization: `Bearer ${localStorage.getItem('token')}`
}
});
return next.handle(request);
}
}
Angular 服务
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ServiceService {
constructor(private http: HttpClient) { }
api_user_url = 'http://localhost:8095';
getAllApiUsers(): Observable<any> {
return this.http.get(this.api_user_url + "/allUser");
}
setUserLogin(obj):Observable<any>{
return this.http.post(this.api_user_url +"/login", obj);
}
}
调用方法
public getAllUserList() {
console.log("I am calling");
this.service.getAllApiUsers()
.subscribe(data => {
this.alluser = data;
console.log(data);
})
}
浏览器网络
令牌的本地存储
浏览器控制台错误信息
Spring Boot Java 控制台错误
答案#1
我认为你问题的正确答案在 JwtSecurityConfig 中。你需要添加允许 OPTIONS 调用,以便在不请求身份验证令牌的情况下通过 JWT 安全验证。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
// Add this line to your code
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("**/rest/**").authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(entryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(authenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
http.headers().cacheControl();
}答案#2
Angular 拦截器看起来不错,但在你的浏览器控制台中有 CORS policy 错误。你的 Angular 应用运行在端口 4200,而你的后端运行在端口 8095(不同的主机)。
我不熟悉spring-boot,但在查看文档后,你应该为后端应用程序添加一些 CORS 策略(生产环境和开发环境不同):
你可以在这里阅读更多内容:https://spring.io/guides/gs/rest-service-cors/
现在你对 /allUser 的请求没有发送……在解决了 CORS 问题后,一切应该能正常工作




