启动过滤器链是很昂贵的,占用了系统很多资源,有时候我们经过一个路径(比如访问静态资源:图片,视频等),不需要进行认证和授权,也就不需要启动过滤器链,为了节约系统资源,可以通过重写configure(WebSecurity web)方法来禁用过滤器链
一些前后端不分离的安全配置概念(了解即可) CSRF攻击CSRF攻击对于无状态应用(前后端分离,使用token,天然免疫)来说是无效的,只有Session类应用需要去预防
当进行登录的时候,如果没有禁用CSRF配置,那么每个POST请求必须携带一个CSRF Token,否则不予授权
为什么会有这样一个配置呢,这首先要从CSRF攻击说起
这种攻击的前提条件是:用户已经登录正常站点
很多网站的登录状态都是一个有时间周期的Session,这种攻击就是利用这一点。
当一个受害用户已经正常的登录过一个站点,并且这个登录的Session还在有效期内时,一个恶意用户发起一个链接给受害用户,比如发起一个银行账户变更通知的链接,然后受害用户登录点击进去,那个恶意页面也和正常的银行页面长得非常像。
这个恶意页面要求受害用户输入他的银行账户,密码,姓名等敏感信息。等受害用户输入之后,这个恶意页面就将这些信息发送给网银,由于受害用户已经登录过网银,并且其Session还没有过期,这些恶意页面发送的数据就等于是在受害用户许可之下发送的,受害用户的网银就被轻松攻破了。
第一种:CSRF Token
由服务器生成,并设置到浏览器Cookie当中,前端每次都会从cookie中将这个token读取出来,服务端要求每个请求都需要带上这个token。提交到服务端之后,服务端会比较CSRF Token,看他是不是和服务端保存在Session中的token一致。这个token每个请求都是不一样的
第二种:在响应当中设置Cookie的SameSite属性
private AuthenticationSuccessHandler jsonLoginSuccessHandler(){ return (req,res,auth) ->{ //.. Collection<String > headers = res.getHeaders(HttpHeaders.SET_COOKIE); res.addHeader(HttpHeaders.SET_COOKIE,String.format("%s; %s",header,"SameSite=Strict")); }; }即在响应当中的Cookie当中设置SameSite属性
但是这个对于浏览器兼容性来说不友好,ie不支持。
所以现在主流还是CSRF Token方法
设置CSRF http.csrf(csrf -> { //保存策略,可以保存在在session(HttpSessionCsrfTokenRepository)或者cookie(CookieCsrfTokenRepository)中 csrf.csrfTokenRepository() //忽略哪些路径 .ignoringRequestMatchers() //哪些需要保护 .requireCsrfProtectionMatcher(); }) Remember me 功能基于Session的功能:Session过期后,用户不需要登录就能直接访问
SpringSecurity提供开箱即用的配置rememberMe
原理:使用Cookie存储用户名,过期时间,以及一个Hash,Hash:md5(用户名+过期时间+密码+key)
当用户访问的时候,会判断Session有没有过期,如果过期了,就直接导到登录页。
如果没有过期,服务端就根据用户名,从数据库里面查到的用户名,密码,过期时间,key,进行md5加密,然后与客户端提交的md5进行对比,如果一致,则认证成功。
注意:md5加密中有密码,也就是说如果用户修改了密码,则需要重新登录。
http.rememberMe(rememberMe -> { //存储策略, rememberMe.tokenRepository() //设置Cookie名称 .rememberMeCookieName() //有效期设置,单位s .tokenValiditySeconds() //设置用户查询服务,实现UserDetailsService接口的类,提供根据用户名查询用户的方法 .userDetailsService() //是否用安全的Cookie .useSecureCookie(); }) 退出前后端不分离的退出设置
http .logout(logout -> { //退出登录的url logout.logoutUrl() //退出登录成功,重定向的url .logoutSuccessUrl() //设置LogoutHandler,自定义退出登录逻辑 .addLogoutHandler() //删除Cookies .deleteCookies() //取消Session .invalidateHttpSession() //清理认证 .clearAuthentication(); })前后端分离的登陆和退出采用增加过滤器或者接口的方式,不需要使用这个配置
Spring Security过滤器链 过滤器其实任何的Spring Web程序,在本质上都是一个Servlet程序