鉴权的四种方式

前后端常见的几种鉴权方式

  1. HTTP Basic Authentication
  2. session-cookie
  3. Token
  4. OAuth

HTTP Basic Authentication

这种授权方式是浏览器遵守http协议实现的基本授权方式,HTTP协议进行通信的过程中,HTTP协议定义了基本认证允许HTTP服务器对客户端进行用户身份证的方法。
认证过程:

  1. 客户端向服务器请求数据,请求的内容可能是一个网页或者是一个ajax异步请求,此时,假设客户端尚未被验证,则客户端提供如下请求至服务器:
  Get /index.html HTTP/1.0 
  Host:www.google.com
  1. 服务器向客户端发送验证请求代码401,(WWW-Authenticate: Basic realm=”google.com”这句话是关键,如果没有客户端不会弹出用户名和密码输入界面)服务器返回的数据大抵如下:
  HTTP/1.0 401 Unauthorised 
  Server: SokEvo/1.0 
  WWW-Authenticate: Basic realm=”google.com” 
  Content-Type: text/html 
  Content-Length: xxx
  1. 当符合http1.0或1.1规范的客户端(如IE,FIREFOX)收到401返回值时,将自动弹出一个登录窗口,要求用户输入用户名和密码。
  2. 用户输入用户名和密码后,将用户名及密码以BASE64加密方式加密,并将密文放入前一条请求信息中,则客户端发送的第一条请求信息则变成如下内容。d2FuZzp3YW5n表示加密后的用户名及密码(用户名:密码 然后通过base64加密,加密过程是浏览器默认的行为,不需要我们人为加密,我们只需要输入用户名密码即可)
  Get /index.html HTTP/1.0 
  Host:www.google.com 
  Authorization: Basic d2FuZzp3YW5n
  1. 服务器收到上述请求信息后,将 Authorization 字段后的用户信息取出、解密,将解密后的用户名及密码与用户数据库进行比较验证,如用户名及密码正确,服务器则根据请求,将所请求资源发送给客户端。

session-cookie

2.1 Cookie
Http协议是一个无状态的协议,服务器不会知道到底是哪一台浏览器访问了它,因此需要一个标识用来让服务器区分不同的浏览器。cookie 就是这个管理服务器与客户端之间状态的标识。
cookie 的原理是,浏览器第一次向服务器发送请求时,服务器在 response 头部设置 Set-Cookie 字段,浏览器收到响应就会设置 cookie 并存储,在下一次该浏览器向服务器发送请求时,就会在 request 头部自动带上 Cookie 字段,服务器端收到该 cookie 用以区分不同的浏览器。当然,这个 cookie 与某个用户的对应关系应该在第一次访问时就存在服务器端,这时就需要 session 了。

2.2 Session
session 是会话的意思,浏览器第一次访问服务端,服务端就会创建一次会话,在会话中保存标识该浏览器的信息。它与 cookie 的区别就是 session 是缓存在服务端的,cookie 则是缓存在客户端,他们都由服务端生成,为了弥补 Http 协议无状态的缺陷。

2.3 Session-cookie认证

  1. 服务器在接受客户端首次访问时在服务器端创建seesion,然后保存seesion(我们可以将seesion保存在 内存中,也可以保存在redis中,推荐使用后者),然后给这个session生成一个唯一的标识字符串,然后在 响应头中种下这个唯一标识字符串。
  2. 签名。这一步通过秘钥对sid进行签名处理,避免客户端修改sid。(非必需步骤)
  3. 浏览器中收到请求响应的时候会解析响应头,然后将sid保存在本地cookie中,浏览器在下次http请求的请求头中会带上该域名下的cookie信息。
  4. 服务器在接受客户端请求时会去解析请求头cookie中的sid,然后根据这个sid去找服
    在这里插入图片描述
    使用session-cookie做登录认证时,登录时存储session,退出登录时删除session,而其他的需要登录后才能操作的接口需要提前验证是否存在session,存在才能跳转页面,不存在则回到登录页面。

Token

token 是一个令牌,浏览器第一次访问服务端时会签发一张令牌,之后浏览器每次携带这张令牌访问服务端就会认证该令牌是否有效,只要服务端可以解密该令牌,就说明请求是合法的,令牌中包含的用户信息还可以区分不同身份的用户。一般 token 由用户信息、时间戳和由 hash 算法加密的签名构成。

3.1 Token认证流程

  1. 客户端使用用户名跟密码请求登录。
  2. 服务端收到请求,去验证用户名与密码。
  3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端。
  4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里。
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token。
  6. 服务端收到请求,然后去验证客户端请求里面带着的 Token(request头部添加Authorization),如果验证成功,就向客户端返回请求的数据 ,如果不成功返回401错误码,鉴权失败。

3.2 JWT
基于 token 的解决方案有许多,常用的是JWT。

在这里插入图片描述
客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。
此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization字段里面。另一种做法是,跨域的时候,JWT 就放在 POST 请求的数据体里面。

3.2.1 JWT组成部分
在这里插入图片描述
实际的JWT就像上边这样,它是一个很长的字符串,中间用点(.)分隔成三个部分。注意,JWT 内部是没有换行的,这里只是为了便于展示,将它写成了几行。它由三部分组成:Header(头部)、Payload(负载)、Signature(签名),写成一行就是 Header.Payload.Signature。

Header
Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。

{
  "alg": "HS256",
  "typ": "JWT"
}

上面代码中,alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT。
最后,将上面的 JSON 对象使用 Base64URL 算法(详见后文)转成字符串。

Payload
Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。

iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号

除了官方字段,你还可以在这个部分定义私有字段,下面就是一个例子。

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

注意,JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。
这个 JSON 对象也要使用 Base64URL 算法转成字符串。

Signature
Signature 部分是对前两部分的签名,防止数据篡改。
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。

3.2.2 JWT几个特点

(1)JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
(2)JWT 不加密的情况下,不能将秘密数据写入 JWT。
(3)JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
(4)JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
(5)JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
(6)为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。

OAuth

OAuth(Open Authorization)是一个开放标准,允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方网站或分享他们数据的所有内容,为了保护用户数据的安全和隐私,第三方网站访问用户数据前都需要显式的向用户征求授权。
OAuth协议又有1.0和2.0两个版本。相比较1.0版,2.0版整个授权验证流程更简单更安全,也是目前最主要的用户身份验证和授权方式。

4.1 OAuth认证流程

OAuth就是一种授权机制。数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据。系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使用。
OAuth有四种获取令牌的方式,不管哪一种授权方式,第三方应用申请令牌之前,都必须先到系统备案,说明自己的身份,然后会拿到两个身份识别码:客户端 ID(client ID)和客户端密钥(client secret)。这是为了防止令牌被滥用,没有备案过的第三方应用,是不会拿到令牌的。
在前后端分离的情境下,我们常使用授权码方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌。

OAuth 2.0 协议流程:
在这里插入图片描述

resource owner,资源所有者,能够允许访问受保护资源的实体。如果是个人,被称为 end-user。
resource server,资源服务器,托管受保护资源的服务器。
client,客户端,使用资源所有者的授权代表资源所有者发起对受保护资源的请求的应用程序。如:web网站,移动应用等。
authorization server,授权服务器,能够向客户端颁发令牌。
user-agent,用户代理,帮助资源所有者与客户端沟通的工具,一般为 web 浏览器,移动 APP 等。

上图详细的描述了这四个角色之间的步骤流程:

(A) Client 请求 Resource Owner 的授权。授权请求可以直接向 Resource Owner 请求,也可以通过 Authorization Server 间接的进行。
(B) Client 获得授权许可。
© Client 向 Authorization Server 请求访问令牌。
(D) Authorization Server 验证授权许可,如果有效则颁发访问令牌。
(E) Client 通过访问令牌从 Resource Server 请求受保护资源。
(F) Resource Server 验证访问令牌,有效则响应请求。

     +--------+                               +---------------+
     |        |--(A)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(B)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(C)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(D)----- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(E)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(F)--- Protected Resource ---|               |
     +--------+                               +---------------+
                      Abstract Protocol Flow

4.2 授权

一个客户端想要获得授权,就需要先到服务商那注册你的应用。一般需要你提供下面这些信息:

  • 应用名称
  • 应用网站
  • 重定向 URI 或回调 URL(redirect_uri)

重定向 URI 是服务商在用户授权(或拒绝)应用程序之后重定向用户的地址,因此也是用于处理授权代码或访问令牌的应用程序的一部分。在你注册成功之后,你会从服务商那获取到你的应用相关的信息:

  • 客户端标识 client_id
  • 客户端密钥 client_secret

client_id 用来表识客户端(公开),client_secret 用来验证客户端身份(保密)。

4.2.1 授权类型

OAuth 2.0 列举了四种授权类型,分别用于不同的场景:

  • Authorization Code(授权码 code):服务器与客户端配合使用。
  • Implicit(隐式token):用于移动应用程序或 Web 应用程序(在用户设备上运行的应用程序)。
  • Resource Owner Password Credentials(资源所有者密码凭证password):资源所有者和客户端之间具有高度信任时(例如,客户端是设备的操作系统的一部分,或者是一个高度特权应用程序),以及当其他授权许可类型(例如授权码)不可用时被使用。
  • Client Credentials(客户端证书client_credentials):当客户端代表自己表演(客户端也是资源所有者)或者基于与授权服务器事先商定的授权请求对受保护资源的访问权限时,客户端凭据被用作为授权许可。

授权码模式

该方式需要资源服务器的参与,应用场景大概是:

资源拥有者(用户)需要登录客户端(APP),他选择了第三方登录。
客户端(APP)重定向到第三方授权服务器。此时客户端携带了客户端标识(client_id),那么第三方就知道这是哪个客户端,资源拥有者确定(拒绝)授权后需要重定向到哪里。
用户确认授权,客户端(APP)被重定向到注册时给定的 URI,并携带了第三方给定的 code。
在重定向的过程中,客户端拿到 code 与 client_id、client_secret 去授权服务器请求令牌,如果成功,直接请求资源服务器获取资源,整个过程,用户代理是不会拿到令牌 token 的。
客户端(APP)拿到令牌 token 后就可以向第三方的资源服务器请求资源了。

	 +----------+
     | Resource |
     |   Owner  |
     |          |
     +----------+
          ^
          |
         (B)
     +----|-----+          Client Identifier      +---------------+
     |         -+----(A)-- & Redirection URI ---->|               |
     |  User-   |                                 | Authorization |
     |  Agent  -+----(B)-- User authenticates --->|     Server    |
     |          |                                 |               |
     |         -+----(C)-- Authorization Code ---<|               |
     +-|----|---+                                 +---------------+
       |    |                                         ^      v
      (A)  (C)                                        |      |
       |    |                                         |      |
       ^    v                                         |      |
     +---------+                                      |      |
     |         |>---(D)-- Authorization Code ---------'      |
     |  Client |          & Redirection URI                  |
     |         |                                             |
     |         |<---(E)----- Access Token -------------------'
     +---------+       (w/ Optional Refresh Token)

   Note: The lines illustrating steps (A), (B), and (C) are broken into
   two parts as they pass through the user-agent.

                     Figure 3: Authorization Code Flow

具体说明,这里以 coding 和 github 为例。当我想在 coding 上通过 github 账号登录时:
1、GET 请求 点击登录,重定向到 github 的授权端点:

https://github.com/login/oauth/authorize?
  response_type=code&
  client_id=a5ce5a6c7e8c39567ca0&
  redirect_uri=https://coding.net/api/oauth/github/callback&
  scope=user:email
字段描述
response_type必须,固定为 code,表示这是一个授权码请求。
client_id必须,在 github 注册获得的客户端 ID。
redirect_uri可选,通过客户端注册的重定向 URI(一般要求且与注册时一致)。
scope可选,请求资源范围,多个空格隔开。
state可选(推荐),如果存在,原样返回给客户端。

返回值:

https://coding.net/api/oauth/github/callback?code=fb6a88dc09e843b33f
字段描述
code必须。授权码
state如果出现在请求中,必须包含。

授权错误
第一种,客户端没有被识别或错误的重定向 URI,授权服务器没有必要重定向资源拥有者到重定向URI,而是通知资源拥有者发生了错误。

第二种,客户端被正确地授权了,但是其他某些事情失败了。这种情况下下面地错误响应会被发送到客户端,包括在重定向 URI 中。

https://coding.net/api/oauth/github/callback?
  error=redirect_uri_mismatch&
  error_description=The+redirect_uri+MUST+match+the+registered+callback+URL+for+this+application.&
  error_uri=https%3A%2F%2Fdeveloper.github.com%2Fapps%2Fmanaging-oauth-apps%2Ftroubleshooting-authorization-request-errors%2F%23redirect-uri-mismatch
字段描述
error必须,必须是预先定义的错误码。
error_description可选,错误描述
error_uri可选,指向可解读错误的 URI
state必须,如果出现在授权请求中

2、POST 请求 获取令牌 token,当获取到授权码 code 后,客户端需要用它获取访问令牌:

https://github.com/login/oauth/access_token?
  client_id=a5ce5a6c7e8c39567ca0&
  client_secret=xxxx&
  grant_type=authorization_code&
  code=fb6a88dc09e843b33f&
  redirect_uri=https://coding.net/api/oauth/github/callback
字段描述
client_id必须,客户端标识。
client_secret必须,客户端密钥。
grant_type必须,固定为 authorization_code/refresh_token。
code必须,上一步获取到的授权码。
redirect_uri必须,完成授权后的回调地址,与注册时一致。

返回值:

{
  "access_token":"a14afef0f66fcffce3e0fcd2e34f6ff4",  //这个就是最终获取到的令牌。
  "token_type":"bearer",    //令牌类型,常见有 bearer/mac/token(可自定义)。
  "expires_in":3920,   //失效时间。
  "refresh_token":"5d633d136b6d56a41829b73a424803ec"  //刷新令牌,用来刷新 access_token。
}

3、获取资源服务器资源,拿着 access_token 就可以获取账号的相关信息了:

curl -H "Authorization: token a14afef0f66fcffce3e0fcd2e34f6ff4" https://api.github.com/user

4、POST 请求 刷新令牌

我们的 access_token 是有时效性的,当在获取 github 用户信息时,如果返回 token 过期:

https://github.com/login/oauth/access_token?
  client_id=a5ce5a6c7e8c39567ca0&
  client_secret=xxxx&
  redirect_uri=https://coding.net/api/oauth/github/callback&
  grant_type=refresh_token&
  refresh_token=5d633d136b6d56a41829b73a424803ec
字段描述
client_id必须,客户端标识。
client_secret必须,客户端密钥。
grant_type必须,固定为 authorization_code/refresh_token。
refresh_token必须,上面获取到的 refresh_token
redirect_uri必须,完成授权后的回调地址,与注册时一致。

返回值:

{
  "access_token":"a14afef0f66fcffce3e0fcd2e34f6ee4",
  "token_type":"bearer",
  "expires_in":3920,
  "refresh_token":"4a633d136b6d56a41829b73a424803vd"
}

refresh_token 只有在 access_token 过期时才能使用,并且只能使用一次。当换取到的 access_token 再次过期时,使用新的 refresh_token 来换取 access_token

  +--------+                                           +---------------+
  |        |--(A)------- Authorization Grant --------->|               |
  |        |                                           |               |
  |        |<-(B)----------- Access Token -------------|               |
  |        |               & Refresh Token             |               |
  |        |                                           |               |
  |        |                            +----------+   |               |
  |        |--(C)---- Access Token ---->|          |   |               |
  |        |                            |          |   |               |
  |        |<-(D)- Protected Resource --| Resource |   | Authorization |
  | Client |                            |  Server  |   |     Server    |
  |        |--(E)---- Access Token ---->|          |   |               |
  |        |                            |          |   |               |
  |        |<-(F)- Invalid Token Error -|          |   |               |
  |        |                            +----------+   |               |
  |        |                                           |               |
  |        |--(G)----------- Refresh Token ----------->|               |
  |        |                                           |               |
  |        |<-(H)----------- Access Token -------------|               |
  +--------+           & Optional Refresh Token        +---------------+

               Figure 2: Refreshing an Expired Access Token

隐式模式、资源所有者密码模式、和客户端模式以后更新。

文章参考:https://deepzz.com/post/what-is-oauth2-protocol.html
https://juejin.im/post/5d67662ee51d45621655353f#heading-1

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值