Spring Security 调研
前言
Spring Security 是 Spring 提供的用于用户权限认证授权的框架。
- 官方文档:https://docs.spring.io/spring-security/site/docs/5.2.2.BUILD-SNAPSHOT/reference/htmlsingle/
- 快速开始:https://spring.io/guides/gs/securing-web/
系统设计要求
要实现用户权限认证授权,主流的设计要求系统中有四个部分:用户、角色、权限、资源,即:
- 用户:要求访问资源的对象,比如张三;
- 角色:具有某些权限的对象,比如普通用户、管理员、订单管理员等;
- 权限:或者说是授权,每条授权记录某个角色可以访问某个资源;
- 资源:代表系统中某个资源,通常用 url 代表,比如 https://xxx.com/api/v1/order;
它们的关系如下:
如图所示,要实现用户权限认证和授权通常要求数据库中要有五张表,分别是:用户表、用户角色表、角色表、资源表、角色资源表(角色授权表)。Spring Security 框架也以以上设计为基础。
RBAC
业界通常基于 RBAC 实现授权。RBAC 可以理解为两种,或者分为两种:
- 基于角色的访问控制(Role-Based Access Control):根据角色进行权限判断,比如用户要查询员工的工资,就判断用户是否具有总经理的角色,如果有就允许查询;
流程如下:
优点:查询快,查一遍用户角色表即可;缺点:需要什么权限就加具有这个权限的角色,代码写起来会比较繁琐,不够灵活;
- 基于资源的访问控制(Resource-Based Access Control):根据资源进行权限判断,比如用户要查询员工的工资,就判断用户是否具有访问工资这个资源的权限,比如有,就允许查询;
流程如下:
优点:直接根据资源进行权限判断,粒度小,足够灵活;缺点:查询慢,需要查两遍表; 总的来说,以上两种方式,基于资源的访问控制,粒度小,足够灵活,推荐采用。一般来说,角色授权表和用户角色表不会很大,查询表的那些时间消耗可以接受。
Spring Security 快速开始
首先为 maven 项目添加 Spring Security 的依赖:pom.xml
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
...
</dependencies>
使用 Spring Security 实现用户角色定义,即规定用户具有哪些角色:
UserBuilder users = User.withDefaultPasswordEncoder(); // 密码编码器
User user = users
.username("user")
.password("password")
.roles("USER") // 当前用户具有 USER 角色
.build();
User admin = users
.username("admin")
.password("password")
.roles("USER","ADMIN") // 当前用户具有 USER 和 ADMIN 两种角色
.build();
使用 Spring Security 实现权限拦截,即规定资源需要哪些角色才能访问:
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorizeRequests -> 1
authorizeRequests
.antMatchers("/resources/**", "/signup", "/about").permitAll() //这些 url 不需要 2
.antMatchers("/admin/**").hasRole("ADMIN") 3
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')") 4
.anyRequest().authenticated() 5
)
.formLogin(withDefaults());
}
通过以上几步,可以搭建一个简单的用户权限认证和授权系统,除此之外,Spring Security 还具有一些高级功能:
- Password Encoding:密码编码器,上例中使用的是简单的编码器(不编码,直接比较),你还可以选择其他方式对密码编码,比如 md5、BCrypt 等,可供选择编码器有:BCryptPasswordEncoder、Argon2PasswordEncoder、Pbkdf2PasswordEncoder 等;
- 从数据库中对用户授权角色:上例中对用户授权角色写在了代码中,但 Spring Security 也支持从数据库中对用户授权角色;
- 从数据库中对角色授权:同上;
总的来说,Spring Security 实现用户权限认证和授权是比较成熟的,提供的功能比较丰富,初期接入和后期扩展都能应付的来。
Spring Security OAuth2
OAuth2 是第二代的开放认证协议(Open Authorization 2.0),Spring Security OAuth2 是对 OAuth2 协议的一种实现。一般来说,OAuth2 提供两种服务,即授权服务(Authorization Server,也叫做认证服务)和资源服务(Resource Server),授权服务接受一组用户名和密钥,返回一个授权码(token),客户端可以通过授权码(token)访问资源服务。
OAuth2 认证逻辑如下:
举个例子说得更清楚些:
总的来说,如果我们的系统打算提供给第三方登录认证的功能,那么可以通过 Spring Security OAuth2 实现。
Spring Security CAS
CAS 是 Central Authentication Service 的缩写,中央认证服务,一种独立开放指令协议。CAS 适用于分布式和微服务情况,设想这种场景,当系统服务多起来之后,比如订单系统、问题系统等,是否每个服务都要设计一个认证和授权模块进行用户的访问控制,那么不如将认证授权模块提取出来,做一个统一的认证授权中心(CAS)。用户要访问某种资源需要先到 CAS 中统一认证,通过后获取一个授权码,用户拿着授权码通过网关访问对应服务中的资源。
具体实现可参考如下架构:
通过 Spring Security 也可以实现 CAS,参考文档:https://docs.spring.io/spring-security/site/docs/5.2.2.BUILD-SNAPSHOT/reference/htmlsingle/#cas
总的来说,当体量大的时候,可以考虑将认证服务拆出来,站内认证和第三方认证都通过统一认证服务(CAS)进行认证。
参考资料
官方文档
https://docs.spring.io/spring-security/site/docs/5.2.2.BUILD-SNAPSHOT/reference/htmlsingle/Securing a Web Application(一个快速开始)
https://spring.io/guides/gs/securing-web/10.18 CAS Authentication - 官方文档
https://docs.spring.io/spring-security/site/docs/5.2.2.BUILD-SNAPSHOT/reference/htmlsingle/#casOAuth 2.0 的一个简单解释 - 阮一峰
http://www.ruanyifeng.com/blog/2019/04/oauth_design.htmljava进阶教程2天快速入门Spring Security OAuth2.0认证授权 - 哔哩哔哩
https://www.bilibili.com/video/av73730658?from=search&seid=3286423518441432816
原创声明
转载请注明:呓语 » Spring Security 调研