业余在开发一个Spring Boot+Vue+Spring Security OAuth2的一个前后端分离项目,其中遇到不少如跨域、OPTIONS请求处理、PreAuthorize注解无效、Token失效处理等问题,记录如下。
在此项目中,资源服务与授权服务在同一应用中,使用端口8081;前端应用使用端口8080。前端使用axios进行ajax调用。
关于Spring Security OAuth2相关内容,可参考:http://liumoran.cn/topic/detail?id=1
1. 后端处理跨域请求问题
如果前后端部署在不同应用服务器上,后端需要配置跨域访问才成。如未配置跨域访问,浏览器F12打开高度页面的Console界面中,可以看到以下信息:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8081/getLoginUser. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)
Spring Boot中配置跨域请求,可以通过定义Filter的方式实现:
@Component
public class MyCorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin","http://localhost:8080");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT, OPTIONS");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, x-requested-with, X-Custom-Header, Authorization");
chain.doFilter(req, res);
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}
2. OPTIONS报401问题
为什么在正常的请求前要发送OPTIONS请求?
用户登录成功后,当前端往后端发送的请求中包含有Authorization头,并且是跨域请求时,浏览器将会往后端发送对应的OPTIONS请求,以确认后台服务是否支持对受保护资源的跨域访问。
由于OPTIONS请求中并不带有Token,因此请求被Spring Security OAuth2拦截到后,检查发现没有Token,直接返回401给前端页面了。
如何配置?
可以在Spring Security的配置类中配置允许所有OPTIONS请求访问,如下所示:
@Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous()
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "**").permitAll()
.anyRequest().authenticated();
}
其中省略掉了其它的资源访问授权配置。
但在配置后前端访问仍旧报401!!经过排查,按前面所说,我是在Spring Security的配置类中添加这个配置的,但实际上,资源服务器中对请求是否有权限访问的处理,是在资源服务器的配置中进行的,因此在单独的Spring Security配置类中进行配置并不会生效!必须在继承自ResourceServerConfigurerAdapter的配置类中进行该项配置。
在资源服务中,实际上是不需要单独的Spring Security的配置类的,直接使用ResourceServerConfigurerAdapter即可完成对各类资源的授权配置。此时的配置类如下:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfigurer extends ResourceServerConfigurerAdapter {
@Autowired
private RealAuthenticationProvider authenticationProvider;
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("testResource")
.stateless(true);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "**").permitAll()
.antMatchers("/*", "/css/**/*", "/js/**/*", "/icons/**/*", "/upload/*",
"/h2-console/", "/h2-console/**/*", "/topic/**/*").permitAll()
.anyRequest().authenticated()
.and()