Skip to content

认证授权

认证Authentication

验证身份的凭据(例如用户名/用户ID和密码),通过这个凭据,系统得以知道你就是你,也就是说系统存在这个用户

授权Authorization

授权发生在认证之后,授权主要管理访问系统的权限,比如有些特定资源只能具有特定权限的人才能访问,比如admin,有些对系统资源操作,比如删除、添加、更新只能特定人具有

RBAC模型

系统权限控制最常采用的访问控制模型就是RBAC模型

RBAC即基于角色的权限访问控制(Role-Based Access Control),这是一种通过角色关联权限,角色同时又关联用户的授权的方式

一个用户可以拥有若干角色,每一个角色又可以被分配若干权限,这样就构成“用户-角色-权限”的授权模型。在这种模型中,用户与角色、角色与权限之间构成了多对多的关系

alt text

RBAC模型中,权限与角色相关联,用户通过成为包含特定角色的成员而得到这些角色的权限,这就极大地简化了权限的管理

Cookie和Session

Cookie 和 Session 都是用来跟踪浏览器用户身份的会话方式,但是两者的应用场景不太一样。

Cookie 存放在客户端,一般用来保存用户信息

Session 的主要作用就是通过服务端记录用户的状态

Cookie 数据保存在客户端(浏览器端),Session 数据保存在服务器端。相对来说 Session 安全性更高。如果使用 Cookie 的一些敏感信息不要写入 Cookie 中,最好能将 Cookie 信息加密然后使用到的时候再去服务器端解密。

session-cookie身份验证

通过 SessionID 来实现特定的用户,SessionID 一般会选择存放在 Redis 中

使用 Session 的时候需要注意下面几个点:

  • 依赖 Session 的关键业务一定要确保客户端开启了 Cookie

  • 注意 Session 的过期时间

没有cookie,session怎么用

一般是通过 Cookie 来保存 SessionID ,假如使用了 Cookie 保存 SessionID 的方案的话, 如果客户端禁用了 Cookie,那么 Session 就无法正常工作

但是,并不是没有 Cookie 之后就不能用 Session 了,比如可以将 SessionID 放在请求的 url 里面https://javaguide.cn/?Session_id=xxx 。这种方案的话可行,但是安全性和用户体验感降低。当然,为了安全也可以对 SessionID 进行一次加密之后再传入后端。

JWT

JWT(JSON Web Token)是目前最流行的跨域认证解决方案,是一种基于Token的认证授权机制。

JWT本身也是Token,一种规范化之后的JSON结构的Token。

JWT自身包含了身份认证所需要的所有信息,因此,服务器不需要存储session信息。增加了系统的可用性和伸缩性,大大减轻了服务端的压力

使用 JWT 认证可以有效避免 CSRF 攻击,因为 JWT 一般是存在在 localStorage 中,使用 JWT 进行身份验证的过程中是不会涉及到 Cookie 的

JWT的组成

本质是一组字符串,通过.切分成三个为Base64编码的部分:

  • Header(头部):描述JWT的元数据,定义了生成签名的算法以及Token的类型。Header被Base64Url编码后成为JWT的第一部分
  • typ(Type):令牌类型,也就是JWT

  • alg(Algorithm):签名算法,比如HS256

{
  "alg": "HS256",
  "typ": "JWT"
}
  • Payload(载荷):用来存放实际需要传递的数据,包含声明(claims),如sub(subject,主题)、jti(JWT ID)。payload被Base64Url编码后成为JWT的第二部分

claims分为三种类型:

  • Registered claims(注册声明):预定义的声明

  • Public claims(公有声明):JWT签发方可以自定义的声明

  • Private claims(私有声明):JWT签发方因为项目需要而自定义的声明,更符合实际项目场景使用

下面是一些常见的注册声明:
iss(issuer):JWT 签发方。
iat(issued at time):JWT 签发时间。
sub(subject):JWT 主题。
aud(audience):JWT 接收方。
exp(expiration time):JWT 的过期时间。
nbf(not before time):JWT 生效时间,早于该定义的时间的 JWT 不能被接受处理。
jti(JWT ID):JWT 唯一标识。
  • Signature(签名):服务器通过payload、header和一个密钥secret使用Header里面指定的签名算法生,生成的签名会成为JWT的第三部分

JWT身份认证

服务器通过payload、header和secret创建JWT并将JWT发送给客户端。客户端接收到JWT之后,会将其保存在cookie或者localstorage里面,以后客户端发出的所有请求都会携带这个令牌

JWT优势

1、无状态:不需要存储session信息,但也会导致不可控(比如想要在JWT有效期内废弃一个JWT或者更改它的权限的话,并不会立即生效,通常需要等到有效期过后才可以)

2、有效避免CSRF攻击:使用 JWT 进行身份验证不需要依赖 Cookie ,因此可以避免 CSRF 攻击

3、适合移动端应用:

session不适合移动端:

  • 状态管理:移动端应用通常是无状态的

  • 兼容性:移动端应用通常会面向多个平台,如iOS、Android、Web。每个平台对session的管理和存储方式可能不同,可能导致跨平台兼容性的问题

  • 安全性:移动设备通常处于不受信任的网络环境,存在数据泄露和攻击的风险

4、单点登录友好

JWT问题及解决方案

1、注销后JWT仍然有效:

  • 将JWT存入数据库:存到redis,如果需要让某个JWT失效,直接从redis删除即可

  • 黑名单机制:在内存数据库如redis维护一个黑名单,如果想让某个JWT失效的话就直接将这个JWT加入到黑名单即可

  • 修改密钥:为每个用户都创建一个专属密钥,如果想让某个JWT失效,直接修改对应用户的密钥即可

  • 保持令牌的有效期短并经常轮换

2、JWT的续签问题:

session认证的做法:假如 Session 的有效期 30 分钟,如果 30 分钟内用户有访问,就把 Session 有效期延长 30 分钟

  • 类似session认证中的做法:假设服务端给的 JWT 有效期设置为 30 分钟,服务端每次进行校验时,如果发现 JWT 的有效期马上快过期了,服务端就重新生成 JWT 给客户端。客户端每次请求都检查新旧 JWT,如果不一致,则更新本地的 JWT。这种做法的问题是仅仅在快过期的时候请求才会更新 JWT ,对客户端不是很友好。

  • 每次请求都返回新的JWT

  • JWT有效期设置到半夜

  • 用户登录返回两个JWT:

  • 第一个是 accessJWT ,它的过期时间 JWT 本身的过期时间比如半个小时

  • 另外一个是 refreshJWT 它的过期时间更长一点比如为 1 天

refreshJWT 只用来获取 accessJWT,不容易被泄露

3、JWT体积太大

  • 尽量减少JWT Payload(载荷)中的信息,只保留必要的用户和权限信息

  • 在传输JWT之前,使用压缩算法对JWT进行压缩以减少体积

  • 在某些情况下,使用传统的token可能更合适

SSO

SSO(Single Sign On),单点登录。SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统

实现

单点登录

单点登出

支持跨域单点登录

支持跨域单点登出

OAuth2.0

OAuth 是一个行业的标准授权协议,主要用来授权第三方应用获取有限的权限。而 OAuth 2.0 是对 OAuth 1.0 的完全重新设计,OAuth 2.0 更快,更容易实现,OAuth 1.0 已经被废弃

权限系统设计

基于角色的访问控制RBAC

基于角色的访问控制(Role-Based Access Control,RBAC)

原理

通过分析用户的实际情况,基于共同的职责和需求,授予他们不同角色,这种用户->角色->权限间的关系,可以不用再单独管理单个用户权限,用户从授予的角色里面获取所需的权限

基于属性的访问控制ABAC

基于属性的访问控制(Attribute-Bassed Access Control,ABAC)是一种比RBAC模型更加灵活的授权模型,原理是通过各种属性来动态判断一个操作是否可以被允许

思想是基于用户、访问的数据的属性、以及各种环境因素去动态计算用户是否有权限进行操作

原理

一个操作是否被允许是基于对象、资源、操作和环境信息共同动态计算决定的

  • 对象:对象是当前请求访问资源的用户。用户的属性包括ID、个人资源、角色,部门和组织成员身份等

  • 资源:资源是当前用户要访问的资产或对象,例如文件、数据、服务器、甚至API

  • 操作:操作是用户视图对资源进行的操作。常见的操作包括“读取”,“写入”,“编辑”,“复制”和“删除”

  • 环境:环境是每个访问请求的上下文,环境属性包含访问的时间和位置,对象的设备,通信协议和加密强度等。

参考

https://javaguide.cn/system-design/security/basis-of-authority-certification.html