后端用户认证系统构建详解

后端用户认证系统构建详解

一年没更新博客,发现学习到的东西还是要写下来梳理一下,要不很难理解透彻,有遗忘重新学效率也很低

常用的两种用户认证方式

Ⅰ 基于 Session 的身份验证

Session 本身是一个抽象的概念,有多种实现,这里就不讲复杂的多节点服务器下 session 身份验证的实现了,讲最普遍的 Session+Cookie

基于 Session 的身份验证,是最传统的验证方式,工作流程如下:

  1. 用户首次登陆成功时,后端生成一个 sessionId,储存在缓存中(还储存一些用户信息,以 sessionId 为 key)(比如用 Redis),设置一个过期时间,然后再把这个 sessionId 返回给用户的浏览器,浏览器再把 sessionId 储存在 cookie 中。

  2. 再次访问时,服务器会取出 HTTP 请求头内 cookie 中的 sessionId ,然后在缓存中寻找该字串,如果存在,那么该用户已登录(A);如果不存在,那么该用户的登陆已经过期(B)。如果根本没收到 session,说明还没登陆过(C)。

对情况A:验证该用户权限,决定是否放行

对情况B、C:均跳转到登陆界面

  1. 客户端调用后端 logout API时,清除缓存中 sessionId key下所有数据

优点

提供了用户认证功能,使无状态的 HTTP 请求有状态化

缺点

本地储存 cookie 不安全,session 储存占用服务器资源

跨域请求不便/不安全,记个 TODO,下次写写 CORS/CSRF

Ⅱ 基于 Token 的身份验证

基于 Token 的身份验证,近几年越来越常见,特点是服务器不用储存登陆状态信息

基于 Token 的身份验证,工作流程如下:

  1. 用户首次登陆成功时,后端生成一个 token,不在后端储存,把 token 发送给用户,用户拿到 token 后将 token 储存在 localStorage(不储存在 cookie,因为不安全)
  2. 再次访问时,服务器会取出 HTTP 请求头内或是 POST 请求体内的 token,对 token 进行解码、校验,判断 token 是否有效,如果有效,那么该用户已登陆;如果无效,那么该用户的登陆已经过期,或者该 token 是伪造的(B)。如果根本没收到 token,说明还没登陆过(C)。

对情况A:验证该用户权限,决定是否放行

对情况B、C:均跳转到登录界面

Token 是什么?

上述验证的可行性依赖于 token 的结构,token 结构分为数据体签名两个部分,数据体往往是经 Base64 等方式编码生成的字串,其中包含用户名、token 过期时间等信息;签名往往是通过 RS256 等非对称加密算法对数据体信息进行加密得到的。

签名的特点是,只有拥有私钥才可以生成签名,有公钥才可以对签名进行解密(从数学上是严格的,暴力破解的时间花费极大),而私钥会被严密保管在签名者处,公钥则由签名者公开,人人都可以拿到。

上述特点导致一个情况,就是签名无法伪造,但是人人都可以获得签名中的数据,所以有了签名,就可以确认数据体是否被人篡改了

也有使用 SHA256 等 Hash 算法生成签名的,再次对数据体信息进行 Hash 生成的新签名,然后与传递来的签名进行比对,相同则说明没有被篡改,但是这样只有后端可以校验签名,因为只有后端牢牢保管 Hash 的生成密钥,才能确保签名是后端生成而非伪造的。

优点

节省服务器内存,不需要 Session 模式下的大量内存

无 Cookie 不会因此受到 CSRF 攻击

缺点

大量的签名验证 CPU 开销略大

无法主动销毁 token,需要等 token 过期

token 易被劫持攻击

JSON Web Token⭐

JWT的官方简介:

JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

一个 JWT 标准 token 包含三个部分——header、payload、signature,其中 header 和 payload 使用 Base64 编码,signature 使用 header 中注明的算法生成,未编码的 header 和 payload 格式如下:

  • header

header 只有 alg 和 typ 两个 key

{
    'alg': "RS256",
    'typ': "JWT"
}

alg 注明了 signature 的生成算法,typ 注明了该 token 的类型(JWT)

  • payload

payload 的 key 分为三类,分别是 Registered claims、Public claims、Private claims

Registered claims 是 JWT 标准保留的 key,用于 JWT 的验证,这些 key 是可选项

Public claims 和 Private claims 是签发者自定义的,Public claims 的特点是 value 应当都是 唯一标识符 类(Collision resistant),而 Private claims 的特点是允许重复(Not collision resistant)

以上只是个分类,简单记住:payload 除了 Registered claims 外,都是自定义的

{
    //以下是 Registered claims
    "iss": "https://jnn.icu/",
    "aud": "https://pc.jnn.icu/",
    "sub": "1035522103",
    "exp": "1620108643",
    //上面四个是最常见的 Registered claims
    "nbf": "1610108643",
    "iat": "1600108643",
    "jti": "dfd1aa97-6d8d-4575-a0fe-34b96de2bfad",

    //以下是 Public claims
    "uuid": "37729e92-0bf7-426a-97e4-e4558a1c848b",

    //以下是 Private claims
    "name": "jnn",
    "admin": true
}

Registered claims :

iss(Issuser):代表这个JWT的签发主体;

sub(Subject):代表这个JWT的主体,即它的所有人;

aud(Audience):代表这个JWT的接收对象;

exp(Expiration time):是一个时间戳,代表这个JWT的过期时间;

nbf(Not Before):是一个时间戳,代表这个JWT生效的开始时间,意味着在这个时间之前验证JWT是会失败的;

iat(Issued at):是一个时间戳,代表这个JWT的签发时间;

jti(JWT ID):是JWT的唯一标识。


Session 身份验证的实现

Django 提供了一套拓展性很强的用户认证系统,很香

待补充😅


JWT 身份验证的实现

待补充😅

发表评论

发表评论

*

沙发空缺中,还不快抢~