大部分系统开发的第一个功能,基本上都是用户注册、登录,这两个看似简单的功能,实则是任何系统安全的基石。Spring Security 想必都很熟悉,作为一个安全管理框架,提供了丰富的认证机制、授权模型以及安全防护措施,极大简化了安全性的开发过程。本文就围绕 Spring Security 的架构原理、配置方法以及高级特性,高效的构建出一个安全的Web应用。
Spring Security 本质上就是一个过滤器链,所有的访问请求都会经过这些过滤器。如下图
不了解过滤器的可以自行前往了解。
图中的 SecurityFilterChain
就是 Spring Security 的过滤器链,认证、授权以及安全防护(XSS、CSRF等)都是在这些过滤器中完成的。
当项目中引入 Spring Security 启动后,一些默认的 SecurityFilterChain
过滤器会被装载,如下:
其中几个过滤器的命名直接体现了其功能,例如LogoutFilter
、UsernamePasswordAuthenticationFilter
、DefaultLoginPageGeneratingFilter
等。
从DefaultLoginPageGeneratingFilter
生成页面就可以得知:Spring Security 默认是前后端不分离的。
所以,对于现在大多数前后端分离的项目,我们可以通过配置自定义需要哪些过滤器以及如何处理该功能,例如如何认证、认证失败、授权失败的响应等。
开发者使用 Spring Security 最关心应该就是认证了,默认会提供表单认证,也就是生成一个表单页面,填写用户名和密码。如下图
这一功能就是DefaultLoginPageGeneratingFilter
这个过滤器完成的。
用户名和密码默认由InMemoryUserDetailsManager
提供,存储在内存中,这里自然需要我们后续去配置自定义实现。
输入用户名密码后就可以去执行认证流程了,如下图
认证的流程中,我们还需要留意几个接口:
SessionAuthenticationStrategy
,认证成功后,会将用户会话存储在HttpSession
中,在后续会基于HttpSession
进行身份验证,但是对于无状态的应用,这种方式是不可取的。AuthenticationFailureHandler
和AuthenticationSuccessHandler
,默认的认证成功和失败后,会重定向跳转到某个页面,对于前后端分离的项目,这种方式时不可取的,依然需要我们后续去配置自定义实现。通常,在认证时会将用户的权限信息(GrantedAuthority
)加载给UserDetails
,在后续的过滤器会对其进行验证,也就是ExceptionTranslationFilter
和AuthorizationFilter
。
这两个有什么区别?
Spring Security 支持请求URL和方法两种授权方式,即在配置中设置authorizeHttpRequests
以及在方法上面的@PreAuthorize
, @PostAuthorize
注解。
以下是两者验证权限的流程
Spring Security 如何知道我们想要求所有用户都经过身份认证?如何知道我们想要支持基于表单的身份认证?实际上,全靠一个配置类去自定义设置,也就是上面所说的 SecurityFilterChain
。
接下来,就基于配置类构建一个前后端分离集成 Spring Security 的Web应用。
SpringBoot 集成 Spring Security 很简单,去spring或者阿里脚手架下载一个demo,引入相关依赖就可以了,主要是这两个
项目启动后就会弹出【认证流程】中的登录界面。
如何配置就看自己的需求了,本文就以前后端分离、无状态为需求,结合JWT进行配置并实现。
梳理下前后端分离、无状态以及结合JWT,应该如何配置Spring Security。
以上有几个事项直接配置即可,例如cors、csrf、session无状态、自定义登录等。
需要自定义实现的配置事项如下:
UserDetailsService
接口中的loadUserByUsername
。LoginUrlAuthenticationEntryPoint
处理,会重定向到某个URL,需要配置自定义为json响应。SimpleUrlAuthenticationFailureHandler
处理,会重定向到某个URL,需要配置自定义为json响应。SavedRequestAwareAuthenticationSuccessHandler
处理,会重定向到某个URL,需要配置自定义为json响应。AccessDeniedHandlerImpl
处理,会重定向到某个URL,需要配置自定义为json响应。SimpleUrlAuthenticationSuccessHandler
,会重定向到某个URL,需要配置自定义为json响应。这些重定向的操作都是在ExceptionTranslationFilter
中处理的,配置了json响应效果如下
整个配置大概是这样
通过以上简单的配置,就已经实现了前后端分离架构和无状态会话管理。除此之外,项目中还需要实现自定义认证逻辑。
以上的配置来看,当post
请求/login
,传入username
和password
就会执行认证流程,不需要写/login
接口。具体逻辑在AbstractAuthenticationProcessingFilter
这个过滤器。
那我们需要写哪些代码实现自定义认证逻辑?
认证流程(看图)中的AuthenticationManager
,会调用 UserDetailsService
接口中的loadUserByUsername()
,最终返回UserDetails
对象交给Spring Security管理。
具体来说,我们需要创建两个类,一个实现UserDetailsService
接口,重写loadUserByUsername()
加载用户信息,一个实现UserDetails
,定义业务中的用户信息。
loadUserByUsername()
中,我们只需要做几件事:
UserDetails
中,返回。注意,这里不需要多此一举校验密码,你只需将数据库中加密的密码交个UserDetails即可。认证流程中会有这一步骤 ,具体处理在DaoAuthenticationProvider
。
不需要写
/login
接口,认证成功后我想返回token怎么办?
如果有这样的疑问,那你一定是没好好看上面认证流程以及配置:代码中的formConfig.successHandler
配置就是用来响应数据的。
为了方便大家观看,我将所有的代码放在一个文件中,如下图
注意:这只是一个示例代码,供大家学习了解Spring Security,可以参考,不建议直接在项目中使用。有任何问题可以随时交流。
Spring Security 本质上就是一连串的过滤器,当一个请求来临时,这些过滤器会对该请求一一处理,包括登录认证、权限验证以及其他安全防护。也因其灵活性,我们只需有简单的配置加上一些代码就可以快速构建出一个安全性极高的Web应用。对于每次集成Spring Security都需要百度的开发者,希望在看完这篇文章的原理+实战后,可以让你摆脱此烦恼。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。