SpringBoot 前后端分离项目,集成 Spring Security(完整版)
本文讲解使用SpringBoot版本:2.2.6.RELEASE,Spring Security版本:5.2.2.RELEASE
Java流行的安全框架有两种Apache Shiro和Spring Security,其中Shiro对于前后端分离项目不是很友好,最终选用了Spring Security。SpringBoot提供了官方的spring-boot-starter-security
,能够方便的集成到SpringBoot项目中,但是企业级的使用上,还是需要稍微改造下,本文实现了如下功能:
匿名用户访问无权限资源时的异常处理
登录用户是否有权限访问资源
基于redis的分布式session共享
session超时的处理
限制同一账号同时登录最大用户数(顶号)
登录成功和失败后返回json
同时支持3种token存放位置:cookie,http header,request parameter
快速使用,引入依赖
spring-boot-starter-security
用于集成spring security,spring-session-data-redis
集成了redis和spring-session。
定制化接入Spring Security
使用Spring Security为的就是写最少的代码,实现更多的功能,在定制化Spring Security,核心思路就是:重写某个功能,然后配置。
比如你要查自己的用户表做登录,那就实现UserDetailsService接口;
比如前后端分离项目,登录成功和失败后返回json,那就实现AuthenticationFailureHandler/AuthenticationSuccessHandler接口;
比如扩展token存放位置,那就实现HttpSessionIdResolver接口;
等等...
最后,将上述做的更改配置到security里。套路就是这个套路,下边咱们实战一下。
Don't bb, show me code.
1. 处理匿名用户无权访问
实现AuthenticationEntryPoint接口,可以处理匿名用户访问无权限资源时的异常,如下:
需要注意的是,当程序出现异常错误时(比如500),也会进入到commence方法中。
2. 基于数据库的用户登录认证逻辑
从数据库中查出登录用户的信息(如密码)、角色、权限等,然后返回一个UserDetails类型的实体,security会自动根据密码和用户相关状态(是否锁定、是否启停、是否过期等)判断用户登录成功或者失败。
同时LoginUser还实现了CredentialsContainer接口,用户认证成功后,擦除密码,然后返给前端。
3. 登录成功的处理
登录成功后,一般要记录登录日志,然后把认证之后的用户authentication返给前端
4. 登录失败的处理
登录失败后,可以根据不同的AuthenticationException,来区分是为什么登录失败,这里需要有日志打印,然后根据业务需求,返回信息给前端。比如要求是无论什么错误,都返回登录失败,这里的示例是进行了登录失败的区分。
5. 退出登录的回调
和登录成功、失败类似,记录日志,然后返回前端json。
6. 登录超时的处理
用户登录后,当达到超时时间后(session过期),自动将用户退出登录
7. 同一账号同时登录的用户数受限的处理
比如某用户同时登陆的会话数,超过了系统的设置,大白话就是被顶号了,这时会由SessionInformationExpiredStrategy处理。
还有,在线用户被管理员提出后,也会触发。
8. 自定义鉴权的实现
当用户登录后,怎么能判定用户是否有权限访问该资源呢?还记得咱们在【2. 基于数据库的用户登录认证逻辑】,从数据库中会把用户的权限角色查出来了,为咱们现在的鉴权提供的基础。
使用@PreAuthorize
注解,即可保护应用的资源。不过,需要配置 @EnableGlobalMethodSecurity(prePostEnabled = true)
才能使@PreAuthorize
生效
9. 登录用户没有权限访问的处理
用户虽然登录了,但是权限不够访问某些资源,这时候就需要AccessDeniedHandler来处理了
10. 自定义Session解析器
官方实现了Cookie和 Session的解析,在实际的项目中,还会遇到token拼接到URL上的情况,这时候可以HttpSessionIdResolver接口
配置Spring Security
做了这么多的准备工作后,终于到了配置的时候了,Spring Security通过建造者模式,使得配置变得简单。
@EnableWebSecurity
注解用来启用Spring Security,@EnableGlobalMethodSecurity(prePostEnabled = true)
用来使@PreAuthorize
生效。还有一部分细节写在代码的注释里了,这样看起来更方便直观点。
配置完成后,post请求ip:port/login
,就可以看到登录的结果了,如下:
后记
到此,你应该能配置出较为完善的安全框架了,本文的所有代码都已经开源,并且经过了测试。
地址:https://gitee.com/songyinyin/gits
按照本文的思路和步骤,你已经迈过了SpringSecurity最初的一步,它让你对整个Security框架有个大概的了解,当然,肯定会有一些疑问,比如为什么从头到尾没有看到登录的接口?登录的时候,怎么就跳到了UserDetailsService#loadUserByUsername()
方法中的?
不妨留言说说你刚接触SpringSecurity时的疑惑
End.
版权声明: 本文为 InfoQ 作者【读钓】的原创文章。
原文链接:【http://xie.infoq.cn/article/0ea386fba90ce9bd93b9d263e】。文章转载请联系作者。
评论