解决方案-认证与授权
参考文献
行业标准
OAuth 2.0
: 一种授权标准,允许用户在一个站点向其他站点授予对其资源的有限访问权限,而无需获得其凭证(通常是账号密码).举个例子,你在手机上点击「使用微信登录」时都会使用此标准,并且系统会询问你是否同意与该应用共享你的头像、昵称等数据.Open ID Connect
: 这是 OAuth 2.0 的一个超集,他在 OAuth 2.0 之上提供了更多用户信息和获取权限和标准,比如他定义了用户的头像为 picture.JSON Web Tokens
: 一种开放标准,主要用来安全的传输信息,他的格式非常紧凑和独立,解析之后是一种 JSON 格式.Security Assertion Markup Language (SAML)
: 一种基于 XML 的开放数据格式,SAML 允许企业应用程序和内部、外部程序无缝连接.LDAP
: 可以把轻量目录访问协议(Lightweight Directory Access Protocol
,简称LDAP
)理解为一个树型的用来存储用户和组织信息的数据库,常被用来做单点登录(SSO
)和企业员工信息管理.CAS
: 集中式认证服务(Central Authentication Service
,简称CAS
)是一种单点登录协议.它的目的是允许一个用户访问多个应用程序,而只需向认证服务器提供一次凭证(如用户名和密码).这样用户不仅不需在登录 Web 应用程序时重复认证,而且这些应用程序也无法获得密码等敏感信息.
权限模型
ACL
(Access Control Lists
,访问控制列表),通过将主体(用户或用户组)直接和权限(包含操作和资源)关联成列表,控制主体能访问哪些资源.DAC
(Discretionary Access Control
,自主访问控制),可以通过ACL或ACM来实现,特点是拥有权限的主体可以将自身的权限赋予给其他主体或收回,常见于操作系统.MAC
(Mandatory Access Control
,强制访问控制),通过对主体和客体进行安全标记(密级),来判断主体能否对客体进行相关操作,常见于军工行业.RBAC
(Role Based Access Control
,基于角色的访问控制),通过引入“角色”的概念,将主体和权限之间的关系解耦,是常见、成熟、有效的权限模型.ABAC
(Attribute Based Access Control
,基于属性的访问控制),通过动态计算一个或一组属性是否满足某种条件来进行授权判断,常用于公有云,不同场景下形态各异.
OAuth 2.0
-
OAuth 2.0
授权的核心就是颁发访问令牌、使用访问令牌 -
OAuth
诞生之初就是为了解决 Web 浏览器场景下的授权问题 -
使用场景
-
授权码许可(
Authorization Code
)类型 -
隐式许可(
Implicit
) -
客户端凭据许可(
Client Credentials
) -
资源拥有者凭据许可(
Resource Owner Password Credentials
)
-
OAuth2
解决问题域和场景
- 开发系统间授权
- 社交联合登录
- 开放API平台
- 现代微服务安全
- 单页浏览器App(HTML5/JS/无状态)
- 无线原生App
- 服务器端WebApp
- 微服务和API间调用
- 企业内部应用认证授权(
IAM/SSO
)
基本概念
access_token
: 访问令牌,必选项.token_type
: 令牌类型,该值⼤⼩写不敏感,必选项.expires_in
: 过期时间,单位为秒.如果省略该参数,必须其他⽅式设置过期时间.refresh_token
: 更新令牌,⽤来获取下⼀次的访问令牌,可选项.scope
: 权限范围,如果与客户端申请的范围⼀致,此项可省略
授权码授权模式(Authorization Code Grant
)
- ⽤户访问客户端,客户端将⽤户引导向认证服务器.
- ⽤户选择是否给予客户端授权.
- 如⽤户给予授权,认证服务器将⽤户引导向客户端指定的
redirection uri
,同时加上授权码code. - 客户端收到
code
后,通过后台的服务器向认证服务器发送code
和redirection uri
. - 认证服务器验证
code
和redirection uri,
确认⽆误后,响应客户端访问令牌(access token
)和刷新令牌(refresh token
).
详细说明
-
客户端申请认证的URI
https://www.example.com/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read&state=xxx
- 参数说明:
response_type
: 授权类型,必选项,此处的值固定为code
client_id
: 客户端的ID,必选项redirect_uri
: 重定向URI,必选项scope
: 申请的权限范围,可选项state
: 任意值,认证服务器会原样返回,⽤于抵制CSRF(跨站请求伪造)攻击
- 参数说明:
-
服务器回应客户端的URI
https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xxx
- 参数说明:
code
: 授权码,必选项.授权码有效期通常设为10分钟,⼀次性使⽤.该码与客户端ID、重定向URI以及⽤户,是⼀⼀对应关系.state
: 原样返回客户端传的该参数的值
- 参数说明:
-
客户端向认证服务器申请令牌
https://www.example.com/oauth/token?client_id=CLIENT_ID&grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=CALLBACK_URL
- 参数说明:
client_id
: 表示客户端ID,必选项.grant_type
: 表示使⽤的授权模式,必选项,此处的值固定为authorization_code
.code
: 表示上⼀步获得的授权码,必选项.redirect_uri
: 表示重定向URI,必选项,且必须与A步骤中的该参数值保持⼀致.
- 注意: 协议⾥没有提及
client_secret
参数,建议可以使⽤此参数进⾏客户端的⼆次验证.
- 参数说明:
-
响应申请令牌的数据
{ "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example","expires_in":3600,"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "example_parameter":"example_value" }
- 参数说明:
access_token
: 访问令牌,必选项.token_type
: 令牌类型,该值⼤⼩写不敏感,必选项.expires_in
: 过期时间,单位为秒.如果省略该参数,必须其他⽅式设置过期时间.refresh_token
: 更新令牌,⽤来获取下⼀次的访问令牌,可选项.scope
: 权限范围,如果与客户端申请的范围⼀致,此项可省略.
- 参数说明:
使用场景
- 授权码模式是最常⻅的⼀种授权模式,在oauth2.0内是最安全和最完善的. 适⽤于所有有Server端的应⽤,如Web站点、有Server端的⼿机客户端. 可以得到较⻓期限授权.
密码模式(Resource Owner Password Credentials Grant
)
- ⽤户向客户端提供⽤户名和密码.
- 客户端将⽤户名和密码发给认证服务器,向后者请求令牌.
- 认证服务器确认⽆误后,向客户端提供访问令牌.
详细说明
-
客户端发出https请求
https://www.example.com/token?grant_type=password&username=USERNAME&password=PASSWORD&client_id=CLIENT_ID
- 参数说明
grant_type
: 授权类型,此处的值固定为password
,必选项.username
: ⽤户名,必选项.password
: ⽤户的密码,必选项.scope
: 权限范围,可选项.
- 参数说明
-
向客户端响应数据
{ "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600,"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA" }
- 参数说明
access_token
: 访问令牌,必选项.token_type
: 令牌类型,该值⼤⼩写不敏感,必选项.expires_in
: 过期时间,单位为秒.如果省略该参数,必须其他⽅式设置过期时间.refresh_token
: 更新令牌,⽤来获取下⼀次的访问令牌,可选项.
- 参数说明
使用场景
- 这种模式适⽤于⽤户对应⽤程序⾼度信任的情况.⽐如是⽤户操作系统的⼀部分. 认证服务器只有在其他授权模式⽆法执⾏的情况下,才能考虑使⽤这种模式.
客户端凭证模式(Client Credentials Grant
)
- 客户端向认证服务器进⾏身份认证,并要求⼀个访问令牌.
- 认证服务器确认⽆误后,向客户端提供访问令牌.
详细说明
-
客户端发送https请求
https://www.example.com/token?grant_type=client_credentials&client_id=CLIENT_ID
- 参数说明
grant_type
: 表示授权类型,此处的值固定为client_credentials
,必选项.scope
: 表示权限范围,可选项.
- 参数说明
-
向客户端响应数据
{ "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600,"example_parameter":"example_value" }
- 参数说明:
access_token
: 访问令牌,必选项.token_type
: 令牌类型,该值⼤⼩写不敏感,必选项.expires_in
: 过期时间,单位为秒.如果省略该参数,必须其他⽅式设置过期时间.example_parameter
: 其它参数,可选项.
- 参数说明:
使用场景
- 客户端模式应⽤于应⽤程序想要以⾃⼰的名义与授权服务器以及资源服务器进⾏互动. 例如使⽤了第三⽅的静态⽂件服务
权限系统中,权限变更后处理方法
- 当权限发生变更时,通常需要确保这些更改立即生效,以便用户和系统能够根据最新的权限执行操作
即时更新会话中的权限信息
- 当权限变更时,可以直接修改当前会话中的用户权限数据,使变更立即生效.这可以通过在拦截器或过滤器中检查权限并更新会话来实现.
- 使用Redis存储会话信息,权限变更后,通过Redis获取并更新对应用户的权限数据
使用事件监听机制
- 在 Spring Security 中,可以利用事件监听机制来响应权限变更事件.例如,当用户被分配或移除某个角色时,发布一个自定义事件,然后有监听器捕获该事件并执行相应的权限更新操作.
定期刷新权限缓存
- 如果权限数据不是频繁变更的,可以考虑使用缓存来存储权限信息,并定期刷新缓存.这样可以在保证性能的同时,确保权限信息的准确性.
强制用户重新登录
- 作为一种简单粗暴的方法,当检测到权限变更时,可以要求用户重新登录以获取最新的权限信息.这种方法适用于对实时性要求不高的场景
使用JWT
- JWT可以在令牌中包含用户的权限信息,每次请求时都验证令牌的有效性和权限.当权限变更时,只需重新生成 JWT 并使其失效即可