SPEL(Spring Expression Language)
SpEL 的基本语法
#:用于引用变量或上下文中的对象。例如:#name表示引用变量name。@:用于引用 Spring 容器中的 Bean。例如:@myBean表示引用名为myBean的 Spring Bean。.:用于访问对象的属性或方法。例如:#user.name表示访问user对象的name属性。- 逻辑运算:支持
and、or、!等逻辑运算符。 - 方法调用:可以直接调用对象的方法。例如:
#user.hasRole('ADMIN')。
PreAuthorize
@PreAuthorize 是 Spring Security 提供的一个注解,用于在方法执行前进行权限检查。它支持 SpEL 表达式,并且可以访问一些内置对象和变量。
常见的内置对象和变量
(1) #oauth2
-
这是 Spring Security OAuth2 提供的一个内置对象,用于访问 OAuth2 相关的信息。
-
常用方法:
#oauth2.hasScope('scope'):检查当前用户是否具有指定的 OAuth2 作用域。#oauth2.clientId:获取当前客户端的clientId。#oauth2.isUser():检查当前是否是用户身份(而不是客户端身份)。
(2) # + 方法参数
- 你可以直接使用方法中的参数作为变量。例如:
@PreAuthorize("#name == 'admin'")
public void doSomething(String name) {
// 只有 name 为 admin 时才能调用此方法
}
(3)principal
- 表示当前认证的用户主体(
Principal对象)。 - 通常是一个
UserDetails对象或 OAuth2 用户信息。
(4)authentication
- 表示当前的
Authentication对象,包含用户的认证信息。
(5)hasRole 和 hasAuthority
- 这是 Spring Security 提供的内置方法,用于检查用户是否具有指定的角色或权限。
OAuth2.0
OAuth 2.0 是一种授权框架,允许第三方应用在用户授权的情况下访问用户的资源。
五种的角色:
1. 资源所有者(Resource Owner)
- 定义:资源所有者是拥有受保护资源(如用户数据)的实体,通常是最终用户。
2. 客户端(Client)
- 定义:客户端是请求访问受保护资源的应用程序,可以是 Web 应用、移动应用或后端服务。
3. 授权服务器(Authorization Server)
- 定义:授权服务器负责验证资源所有者的身份并颁发访问令牌。
4. 资源服务器(Resource Server)
- 定义:资源服务器是托管受保护资源的服务器。
5. 用户代理(User Agent)
- 定义:用户代理是资源所有者与客户端、授权服务器交互的工具,通常是浏览器或移动应用。
6. 资源(Resource )
- 定义:例如用户数据、订单信息、照片等
四种授权模式
1. 授权码模式(Authorization Code)
流程
- 客户端将用户重定向到授权服务器的登录页面。
- 用户在授权服务器上登录并授权。
- 授权服务器返回一个授权码给客户端。
- 客户端使用授权码向授权服务器请求访问令牌。
- 授权服务器返回访问令牌,客户端使用该令牌访问资源服务器。
特点
- 安全性高,授权码通过前端传递,访问令牌通过后端交换。
- 支持刷新令牌(Refresh Token)。
应用场景
-
Web 应用:用户通过浏览器访问的网站,如电商平台、博客系统。
- 例子:用户登录淘宝时,淘宝(客户端)会跳转到支付宝(授权服务器)进行授权,支付宝返回授权码,淘宝用授权码换取访问令牌。
-
移动应用:安装在手机上的应用程序,如微信、抖音。
- 例子:用户登录抖音时,抖音(客户端)会跳转到微信(授权服务器)进行授权,微信返回授权码,抖音用授权码换取访问令牌。
案例:用户登录淘宝并查看订单
角色对应
- 资源所有者:用户(淘宝的消费者)。
- 客户端:淘宝(Web 应用)。
- 资源:用户的订单信息。
- 资源服务器:订单服务(存储和管理订单数据的后端服务)。
- 授权服务器:支付宝(负责用户登录和授权)。
- 用户代理:用户的浏览器。
流程
- 用户打开浏览器(用户代理),访问淘宝(客户端)。
- 淘宝将用户重定向到支付宝(授权服务器)的登录页面。
- 用户在支付宝上登录并授权淘宝访问其订单信息(资源)。
- 支付宝 返回一个 授权码 给淘宝(通过浏览器重定向)。
- 淘宝使用授权码向支付宝请求访问令牌。
- 支付宝 验证授权码并返回 访问令牌 给淘宝。
- 淘宝使用访问令牌向 订单服务(资源服务器) 请求用户的订单信息。
- 订单服务验证访问令牌,确认有效后返回订单数据。
- 淘宝将订单信息展示给用户。
2. 隐式模式(Implicit)
流程
- 客户端将用户重定向到授权服务器的登录页面。
- 用户在授权服务器上登录并授权。
- 授权服务器直接将访问令牌返回给客户端(通过 URL 片段)。
特点
- 适用于无法安全存储客户端凭证的场景
- 访问令牌直接通过前端传递,安全性较低,不推荐。
- 不支持刷新令牌。
应用场景
-
单页应用(SPA) :所有页面内容通过 JavaScript 动态加载的 Web 应用,如 Gmail、Google Docs。
- 例子:用户登录 Gmail 时,Gmail(客户端)会跳转到 Google 登录页面(授权服务器),Google 直接将访问令牌返回给 Gmail。
-
移动应用:适用于无法安全存储客户端凭证的场景。
- 例子:某些移动应用可能使用隐式模式简化流程,但安全性较低,不推荐。
案例:用户登录 Gmail 并查看邮件
角色对应
- 资源所有者:用户(Gmail 的用户)。
- 客户端:Gmail(单页应用,SPA)。
- 资源:用户的邮件数据。
- 资源服务器:Gmail邮件服务(存储和管理邮件的后端服务)。
- 授权服务器:Google登录服务(负责用户登录和授权)。
- 用户代理:用户的浏览器。
流程
- 用户打开浏览器(用户代理),访问 Gmail(客户端)。
- Gmail将用户重定向到Google 登录页面(授权服务器)。
- 用户在Google登录页面上登录并授权Gmail 访问其邮件数据(资源)。
- Google直接将访问令牌返回给Gmail(通过 URL 片段)。
- Gmail使用访问令牌向Gmail邮件服务(资源服务器) 请求用户的邮件数据。
- Gmail邮件服务验证访问令牌,确认有效后返回邮件数据。
- Gmail将邮件数据展示给用户。
3. 密码模式(Resource Owner Password Credentials)
流程
- 用户直接将用户名和密码提供给客户端。
- 客户端使用用户名和密码向授权服务器请求访问令牌。
- 授权服务器返回访问令牌。
特点
- 用户凭证直接传递给客户端,安全性较低。
- 适用于高度信任的客户端。
应用场景
-
内部系统:企业内部的应用,如员工管理系统。
- 例子:员工登录公司内部系统时,系统(客户端)直接使用员工的用户名和密码向授权服务器请求访问令牌。
-
受信任的客户端:客户端和授权服务器由同一团队开发和管理。
- 例子:某些企业级应用可能使用密码模式简化流程。
案例:员工登录公司内部系统并查看工资单
角色对应
- 资源所有者:员工(公司内部系统的用户)。
- 客户端:公司内部系统(Web 应用)。
- 资源:员工的工资单数据。
- 资源服务器:工资单服务(存储和管理工资单数据的后端服务)。
- 授权服务器:公司内部的认证服务(负责用户登录和授权)。
- 用户代理:员工的浏览器。
流程
- 员工打开浏览器(用户代理),访问公司内部系统(客户端)。
- 员工在登录页面上输入用户名和密码。
- 公司内部系统使用用户名和密码向公司内部的认证服务(授权服务器) 请求访问令牌。
- 认证服务验证用户名和密码,并返回 访问令牌。
- 公司内部系统使用访问令牌向 工资单服务(资源服务器) 请求员工的工资单数据(资源)。
- 工资单服务验证访问令牌,确认有效后返回工资单数据。
- 公司内部系统将工资单数据展示给员工。
4. 客户端凭证模式(Client Credentials)
流程
- 客户端使用自己的凭证(客户端 ID 和客户端密钥)向授权服务器请求访问令牌。
- 授权服务器返回访问令牌。
特点
- 不需要用户参与,客户端直接访问资源。
- 适用于客户端访问自己的资源。
应用场景
-
后端服务:服务器之间的通信,如微服务架构中的服务调用。
- 例子:订单服务(客户端)需要访问库存服务(资源服务器),订单服务使用自己的凭证向授权服务器请求访问令牌。
-
自动化任务:定时任务或批处理任务。
- 例子:每天凌晨的数据同步任务,任务脚本(客户端)使用自己的凭证向授权服务器请求访问令牌。
案例:订单服务访问库存服务以检查库存
角色对应
- 资源所有者:无(客户端直接访问资源)。
- 客户端:订单服务(后端服务)。
- 资源:库存数据。
- 资源服务器:库存服务(存储和管理库存数据的后端服务)。
- 授权服务器:公司内部的认证服务(负责颁发访问令牌)。
- 用户代理:无(后端服务之间直接通信)。
流程
- 订单服务(客户端) 使用自己的客户端 ID 和客户端密钥向 公司内部的认证服务(授权服务器) 请求 访问令牌。
- 认证服务 验证客户端凭证,并返回 访问令牌。
- 订单服务 使用访问令牌向 库存服务(资源服务器) 请求库存数据。
- 库存服务 验证访问令牌,确认有效后返回库存数据。
- 订单服务 根据库存数据决定是否允许用户下单。
总结对比
| 角色 | 授权码模式 | 隐式模式 | 密码模式 | 客户端凭证模式 |
|---|---|---|---|---|
| 资源所有者 | 淘宝用户 | Gmail 用户 | 公司员工 | 无 |
| 客户端 | 淘宝(Web 应用) | Gmail(SPA) | 公司内部系统(Web 应用) | 订单服务(后端服务) |
| 资源 | 订单信息 | 邮件数据 | 工资单数据 | 库存数据 |
| 资源服务器 | 订单服务 | Gmail 邮件服务 | 工资单服务 | 库存服务 |
| 授权服务器 | 支付宝 | Google 登录服务 | 公司内部的认证服务 | 公司内部的认证服务 |
| 用户代理 | 浏览器 | 浏览器 | 浏览器 | 无 |
备注
Web 应用:通过浏览器访问的应用程序,页面由服务器渲染并返回给浏览器。淘宝、知乎
移动应用:安装在手机或平板上的应用程序,通过应用商店下载。微信、抖音
单页应用(SPA):所有页面内容通过 JavaScript 动态加载,用户操作无需刷新页面。Gmail、腾讯文档
后端服务:运行在服务器上的应用程序,通常为其他应用提供 API 接口。订单服务、库存服务
URL片段:URL片段是URL中#后面的部分,如https://example.com/page#section1
Spring Security OAuth关键类
(1)授权服务器相关
-
AuthorizationServerConfigurerAdapter:- 用于配置授权服务器的核心行为,如客户端详情、令牌存储、授权端点等。
- 需要重写
configure方法来定义配置。
-
ClientDetailsServiceConfigurer:- 用于配置客户端详情(如
clientId、clientSecret、授权类型等)。 - 通常通过内存或数据库存储客户端信息。
- 用于配置客户端详情(如
-
AuthorizationServerEndpointsConfigurer:- 用于配置授权服务器的端点(如
/oauth/token、/oauth/authorize)。 - 可以指定令牌存储方式、用户详情服务等。
- 用于配置授权服务器的端点(如
-
TokenStore:-
用于存储令牌(如访问令牌、刷新令牌)。
-
常见的实现类:
InMemoryTokenStore:将令牌存储在内存中。JdbcTokenStore:将令牌存储在数据库中。JwtTokenStore:用于 JWT 令牌。
-
-
AuthorizationServerSecurityConfigurer:- 用于配置授权服务器的安全规则(如
/oauth/token_key端点的访问权限)。
- 用于配置授权服务器的安全规则(如
(2)资源服务器相关
-
ResourceServerConfigurerAdapter:- 用于配置资源服务器的行为,如资源保护规则、令牌解析方式等。
-
ResourceServerSecurityConfigurer:- 用于配置资源服务器的安全规则(如令牌验证、资源 ID 等)。
-
DefaultTokenServices:- 默认的令牌服务实现,用于管理令牌的创建、存储和验证。
(3)OAuth 2.0 令牌相关
-
OAuth2AccessToken:- 表示 OAuth 2.0 的访问令牌。
-
OAuth2RefreshToken:- 表示 OAuth 2.0 的刷新令牌。
-
JwtAccessTokenConverter:- 用于将 JWT(JSON Web Token)与 OAuth 2.0 令牌进行转换。
(4)用户认证相关
-
UserDetailsService:- 用于加载用户详情(如用户名、密码、权限等)。
- 通常与 Spring Security 的认证机制结合使用。
-
AuthenticationManager:- 用于处理用户认证。