Token(令牌)就是一个长的字符串,有了合法的令牌才被允许访问服务器提供的接口。
在说明token之前,先看一下OAuth协议。
OAuth
OAuth是一种开放的协议,为桌面程序或者基于BS的web应用提供了一种简单的,标准的方式去访问需要用户授权的API服务。
在没有oauth服务下,如果一个用户拥有两项服务:一项服务是图片在线存储服务A,另一个是图片在线打印服务B。由于服务A与服务B是由两家不同的服务提供商提供的,所以用户在这两家服务提供商的网站上各自注册了两个用户,假设这两个用户名各不相同,密码也各不相同。当用户要使用服务B打印存储在服务A上的图片时,用户该如何处理?
方法一:用户可能先将待打印的图片从服务A上下载下来并上传到服务B上打印,这种方式安全但处理比较繁琐,效率低下。
方法二:用户将在服务A上注册的用户名与密码提供给服务B,服务B使用用户的帐号再去服务A处下载待打印的图片,这种方式效率是提高了,但是安全性大大降低了,服务B可以使用用户的用户名与密码去服务A上查看甚至篡改用户的资源。
这也促使OAUTH项目组的产生。OAuth是由Blaine Cook、Chris Messina、Larry Halff 及David Recordon共同发起的,目的在于为API访问授权提供一个开放的标准。OAuth规范的1.0版于2007年12月4日发布。
The abstract OAuth 2.0 flow illustrated below describes theinteraction
between the client, resource owner, authorization server,and resource server.( https://tools.ietf.org/html/rfc6749)
框架中client即第三方应用,Resource Owner(RO)指的就是资源实际拥有者,Resource Server则是指资源存放的地方(可以对外提供服务),Protected Resource指的是Owner的受保护的资源(如用户信息、存放在服务器上的资源等),authorization
server是授权服务器,它认证RO的身份,为RO提供授权审批流程,并最终颁发授权令牌(Access Token)。为了便于协议的描述,这里只是在逻辑上把AS与RS区分开来;在物理上,AS与RS的功能可以由同一个服务器来提供服务。
从框架上不难看出,要获取access token必须先得到用户授权(authorzation grant),那么如果获取这么用户授权呢?OAuth 2.0定义了四种类型的授权类型:
授权码模式(authorization code)
隐含模式(implicit)
密码模式(resource owner password credentials)
客户端模式(client credentials)
这里主要介绍一下授权码模式,它是当今主流的授权类型,如第三方应用要使用微信登录、微博登录等。
授权码模式
The authorization code grant type is used to obtain both access tokens andrefresh tokens and is optimized for confidential clients.Since this is aredirection-based flow, the client must be capable of interacting with theresource owner's user-agent (typically a web browser) and capable of receivingincoming requests (via redirection) from the authorization server.
步骤A中,
The client initiates the flow by directing the resource owner's user-agentto the authorization endpoint. Theclient includes its client identifier(The authorization server issues theregistered client a client identifier -- a unique string representing theregistration information provided by the client. The client identifier is not a secret; it isexposed to the resource owner and MUST NOT be used alone for clientauthentication. The client identifier isunique to the authorization server.
), requested scope, local state, and a redirection URI to which theauthorization server will send the user-agent back once access is granted (ordenied).
如,第三方app使用微信账号登录的时候,向微信授权服务器发起的申请就是(示例)
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx6f3xxx0cs6c24xdf0&redirect_uri=http%3A%2F%2Fw.k189.cn%2Findex.php%2FHuoDong%2FFlowhongbao%2Findex&response_type=code&scope=snsapi_base&state=123&connect_redirect=1#wechat_redirect
步骤B中,
The authorization server authenticates the resource owner (via theuser-agent) and establishes whether the resource owner grants or denies theclient's access request.
这一步中,实际上就是用户进入app,点击微信登录按钮的时候,app会将微信分配的的appId交给用户,让他进入微信授权界面,如果此时用户没有登录,微信会提示登录(当然这不是OAuth2.0客户端部分应该关注的)。假设用户已经登录微信,那么微信看到用户请求的appid,就知道是已经注册的app让他过来的,于是就把该app所能获取的权限摆出来,并询问用户是否允许其获取这些权限。
步骤C中,
Assuming the resource owner grants access, the authorization serverredirects the user-agent back to the client using the redirection URI provided earlier(in the request or during client registration). The redirection URI includes anauthorization code and any local state provided by the client earlier.
如
http://w.k189.cn/index.php/HuoDong/Flowhongbao/index?code=001SM3Mq0NSGpn1HFxOq0lxTLq0SM3ME&state=123
这一步传递code给client,客户端从URL中获取授权码。
上一步中,已经拿到了code(授权码),但这个code 只能表明,用户允许app从微信上获取该用户的数据,如果app直接拿这个code去微信访问数据一定会被拒绝,因为任何人都可以持有code,微信并不知道code持有方就是这个合法的app。之前提到过app在微信上注册时,微信会提供一个secrectID 。appId在上一步中已经用过了,接下来轮到另Secretid了。
步骤D,
The client requests an access token from the authorization server's tokenendpoint by including the authorization code received in the previousstep. When making the request, the clientauthenticates with the authorization server. The client includes theredirection URI used to obtain the authorization code for verification.
如
https://api.weixin.qq.com/sns/oauth2/access_token?appid=wx6f3xx0ce6c24xxdf0&secret=af2f9686ssd49fccdxxx07d5ad603f1684&code=001SM3MsssNSGpn1HFxOq0lxTLq0SM3ME&grant_type=authorization_code
这一步就是使用code和secretid去换取access token。
步骤E,
The authorization server authenticates the client, validates the authorizationcode, and ensures that the redirection URI received matches the URI used toredirect the client in step (C). Ifvalid, the authorization server responds back with an access token and,optionally, a refresh token.
从上面的步骤可以看出,用户始终没有将其用户名与密码等信息提供给使用者(第三方软件),从而更安全。用OAUTH实现的情景将变为:当服务B(打印服务)要访问用户的服务A(图片服务)时,通过OAUTH机制,服务B向服务A发起authorization Request,服务A将引导用户在服务A的网站上登录,并询问用户是否将图片服务授权给服务B。用户同意后,给B一个access token,服务B凭此就可以访问用户在服务A上的图片了。整个过程服务B没有触及到用户在服务A的帐号信息。如下图(来源于网络)所示,图中的字母对应OAUTH流程中的字母:
OAuth 2.0 (RFC 6749) 定义了 Client 如何取得Access Token 的方法。Client 可以用 Access Token 以 Resource Owner 的名义来向 Resource Server 取得Protected Resource, OAuth 2.0 定义Access Token 是 Resource Server 用来认证的唯一方式,有了这个, Resource Server 就不需要再提供其他认证方式,例如账号密码。 然而在 RFC 6749 里面只定义抽象的概念,细节如 Access Token 格式、怎么传到 Resource Server ,以及 Access Token 无效时, Resource Server 怎么处理,都没有定义。所以在 RFC 6750 另外定义了 Bearer Token (token持有人)的用法。
Bearer Token
Bearer Token 是一种 Access Token ,由 Authorization Server 在 Resource Owner 的允许下核发给 Client ,Resource Server 只要认在这个 Token 就可以认定 Client 已经获取 Resource Owner 的许可,不需要用密码学的方式来验证这个 Token 的真伪。
Bearer Authentication
Bearer authentication (also called token authentication) is an HTTP authentication scheme that involves security tokens called bearer tokens. The name “Bearer authentication” can be understood as “give access to the bearer of this token.” The bearer token is a cryptic string, usually generated by the server in response to a login request.
The Bearer authentication scheme was originally created as part of OAuth 2.0 in RFC 6750, but is sometimes also used on its own. Similarly to Basic authentication, Bearer authentication should only be used over HTTPS (SSL).
在拿到bearer token后,我们有3种使用方式
Authorization Request Header Field
When sending the access token in the "Authorization" request header field defined by HTTP/1.1, the client uses the "Bearer" authentication scheme to transmit the access token.
For example:
GET /resource HTTP/1.1
Host: server.example.com
Authorization: Bearer mF_9.B5f-4.1JqM
Clients SHOULD make authenticated requests with a bearer token using the "Authorization" request header field with the "Bearer" HTTP authorization scheme. Resource servers MUST support this method.
Form-Encoded Body Parameter
When sending the access token in the HTTP request entity-body, the client adds the access token to the request-body using the "access_token" parameter.
For example, the client makes the following HTTP request using transport-layer security:
POST /resource HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
access_token=mF_9.B5f-4.1JqM
The entity-body MAY include other request-specific parameters, in which case the "access_token" parameter MUST be properly separated from the request-specific parameters using "&" character(s)。
URI Query Parameter
When sending the access token in the HTTP request URI, the client adds the access token to the request URI query component as defined by "Uniform Resource Identifier (URI): Generic Syntax",using the "access_token" parameter.
For example, the client makes the following HTTP request using transport-layer security:
GET /resource?access_token=mF_9.B5f-4.1JqM HTTP/1.1
Host: server.example.com
The HTTP request URI query can include other request-specific parameters, in which case the "access_token" parameter MUST be properly separated from the request-specific parameters using "&"character(s) 。