最近我开始使用
angularjs和spring mvc实现基于令牌的安全系统.这个想法如下:
1.访问/ user / authenticate以获取安全令牌并将令牌保存到本地存储
2.对于angularJS客户端发送的每个请求,使用拦截器向请求注入X-Auth-Token标头.
1.访问/ user / authenticate以获取安全令牌并将令牌保存到本地存储
2.对于angularJS客户端发送的每个请求,使用拦截器向请求注入X-Auth-Token标头.
在我的Spring后端,我实现了AuthenticationTokenProcessingFilter和CustomAuthenticationEntryPoint.第一个用于从标头中提取令牌并检查它是否有效,第二个用于在未对请求进行身份验证时返回401未授权状态.
请查找有关我的后端代码的一些详细信息
AuthenticationController.java
@RestController @RequestMapping(value="user") public class AuthenticationController { @RequestMapping(value="authenticate",method = RequestMethod.POST) public ResponseEntity<?> login(@RequestParam("email") String email,@RequestParam("password") String password) { //Check if user is valid and return token } }
SecurityConfig.java
public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired UsersRepository usersRepo; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {...} @Override protected void configure(HttpSecurity http) throws Exception { http .addFilterBefore( new AuthenticationTokenProcessingFilter(usersRepo),UsernamePasswordAuthenticationFilter.class) .addFilterBefore(this.corsFilter(),UsernamePasswordAuthenticationFilter.class) .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .csrf().disable().exceptionHandling() .and() .httpBasic() .authenticationEntryPoint(new CustomAuthenticationEntryPoint()) .and() .authorizeRequests() .antMatchers(HttpMethod.POST,"/user/authenticate").permitAll() .antMatchers("/**").authenticated() .anyRequest().authenticated(); } @Bean public CORSFilter corsFilter() { return new CORSFilter(); } }
CORSFilter.java
public class CORSFilter implements Filter { public void doFilter(ServletRequest req,ServletResponse res,FilterChain chain) throws IOException,ServletException { HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin","*"); response.setHeader("Access-Control-Allow-Methods","POST,GET,OPTIONS,DELETE,PUT"); response.setHeader("Access-Control-Max-Age","3600"); response.setHeader("Access-Control-Allow-Headers","Content-Type,Access-Control-Allow-Headers,Authorization,X-Requested-With,Origin,X-Auth-Token"); response.addHeader("Access-Control-Expose-Headers","X-Auth-Token"); chain.doFilter(req,res); } }
现在我使用以下angularjs代码来查询不在防火墙后面的/ user / authenticate端点
return $http.post(baseUrl + 'user/authenticate','email='+username+'&password='+password,{ headers : { 'content-type' : 'application/x-www-form-urlencoded' } } );
当我使用上面的代码时一切正常.但是,如果我从请求中删除headers参数,我的angularjs客户端发送一个OPTION请求(而不是POST请求 – 我想这与我的CORS过滤器有关),我的后端发送401 Unauthorized响应.
你能不能再告诉我为什么会这样?
先感谢您!
我想我有一个类似的(相同的?)问题,我在WebSecurityConfigurerAdapter :: configure(HttpSecurity http)中稍微调整了我的过滤器链来解决它.
我认为在您的情况下会发生的是浏览器发送OPTIONS请求以确定您的服务器是否允许CORS. OPTIONS请求在您的过滤器链中处理,并最终匹配
.antMatchers("/**").authenticated()
现在,您可能最终会进入CustomAuthenticationEntryPoint()并返回401.
你可以添加:
.antMatchers(HttpMethod.OPTIONS,"/user/authenticate/").permitAll()
但是,我认为你之后仍然会遇到问题.当客户端现在想要访问其他资源时,必须在标头中发送令牌.很可能这会导致另一个不包含您的令牌的OPTIONS请求,因此您最终会遇到同样的问题.
所以我做的是明确允许所有OPTIONS请求而不检查身份验证.
.antMatchers(HttpMethod.OPTIONS,"/**").permitAll()
现在你绕过你的安全过滤器,你将不会返回401.我认为这不会影响应用程序的安全性,只要你不在控制器中自己处理OPTIONS请求并允许某人访问关键数据.