OAuth2
OAuth2是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,如qq登陆、微信登陆、微博登陆。
OAuth的产生
需求:有一个“云打印”网站,可以将用户存储在google的照片打印出来。用户为了使用该服务,必须让“云打印”读取自己存储在google上的照片。但google只有得到用户授权才会同意“云打印”读取这些照片。
方案1:用户把用户名密码告诉“云打印”,然后“云打印”去google获取照片并打印。
问题:1、用户的google用户名密码泄露。2、“云打印”拥有了该用户在google网盘上所有的权限,即“云打印”可以访问该用户存储在google网盘上的所有文件。3、google只能使用用户名密码认证,不能使用第三方验证,比如手机验证、邮箱验证。
OAuth2方案:使用OAuth2,”云打印”在获取用户的授权后可以从google获取一个绑定用户的token,”云打印”可以使用这个token去访问用户允许它访问的数据,且token有默认的有效时间,用户也可以手动取消token的有效性。
OAuth2名词
1、Third-party application:即”云打印”
2、Http service:即google
3、Resource Owner:用户
4、User Agent:浏览器
5、Authorization Server:认证服务器,即谷歌专门用来提供认证服务的服务器。
6、Resource Server:资源服务器,即谷歌网盘服务器。
会话机制常用的有两种
session方式:用户发送用户名密码,服务器校验并生成session并发送session id给客户端,客户端保存在cookie中,下次访问携带cookie。
token方式:区别,服务器不生成sesseion id,生成token发送给客户端,客户端可以把token放在cookie中,也可以不放在cookie中,下次访问携带token。
OAuth2使用token方式
OAuth2协议大致流程
+--------+ +---------------+ | |--(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 ---| | +--------+ +---------------+
1、第三方应用(Client)向用户请求授权。
2、用户同意授权。(Grant,同意)
3、第三方应用带着用户的授权向认证服务器请求令牌。(Token,令牌)
4、认证服务器返回令牌。
5、第三方应用带着令牌向资源服务器请求资源。
6、资源服务器返回资源。
Authorization Grant——用户授权有四种模式
1、授权码模式
2、简化模式(隐式模式)
3、密码模式
4、客户端模式
授权码模式
+----------+ | 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)
Resource Owner——个人用户 Client——第三方应用后台服务器 User Agent——用户代理,即浏览器 Authorization Server——认证服务器
CSDN使用qq授权登陆:
1、在csdn.net注册页面点击qq小图标,浏览器访问:https://passport.csdn.net/v1/register/authorization?authType=qq
这是csdn.net的一个地址,authType=qq表示使用qq授权登陆;另外csdn.net还支持github、微博、百度、脉脉的授权登陆
2、Client从认证服务器获取授权码
Client自动调用腾讯对外开放的接口https://graph.qq.com/oauth2.0/show?which=Login&display=pc&client_id=100270989&response_type=code&redirect_uri=https://passport.csdn.net/account/login?pcAuthType=qq&state=test
官网示例,使用x-www-form-urlencoded格式组织参数 GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1 Host: server.example.com
Client携带的参数:response_type=code,表示使用授权码模式;client_id,表示客户端标识,即上图中的Client Identifier,此字符串唯一代表此客户端,此字符串不保密,此字符串要暴露给个人用户;redirect_uri表示重定向url,即上图中的Redirection URI;state为了防止csrf攻击。
用户输入的参数:qq用户名、qq密码,即上图中的 User authenticates
3、认证服务器返回授权码
Authorization Server使浏览器重定向到Client指定的接口,并把Authorization Code添加到redirect_uri后面。Authorization Code在发布不久后必须过期,以降低泄露风险;最大的过期时间推荐为10分钟。Authorization Code只能使用一次;如果再次使用,认证服务器必须拒绝请求,如果可以的话,还应该废除此前基于此Authorization Code发布的token。
官网重定向示例,使用x-www-form-urlencoded格式组织参数
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz
4、Client向认证服务器获取令牌
Client后台服务器使用HTTPS携带Authorization Code访问Authorization Server。
官网示例: POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
//grant_type的值必须是authorization_code,code是上一步认证服务器返回的,redirect_uri必须和获取授权码时的地址相同
5、认证服务器返回令牌
Authorization Server返回Access Token、Refresh Token到Client后台服务器,并使用后台服务器重定向到资源服务器
官网示例: HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache { "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "example_parameter":"example_value" }
简化模式(隐式模式)
简化模式不支持刷新token的发放;第三方没有服务器;第三方通常通过浏览器里的javascrpt和服务提供方交互。
+----------+ | Resource | | Owner | | | +----------+ ^ | (B) +----|-----+ Client Identifier +---------------+ | -+----(A)-- & Redirection URI --->| | | User- | | Authorization | | Agent -|----(B)-- User authenticates -->| Server | | | | | | |<---(C)--- Redirection URI ----<| | | | with Access Token +---------------+ | | in Fragment | | +---------------+ | |----(D)--- Redirection URI ---->| Web-Hosted | | | without Fragment | Client | | | | Resource | | (F) |<---(E)------- Script ---------<| | | | +---------------+ +-|--------+ | | (A) (G) Access Token | | ^ v +---------+ | | | Client | | | +---------+
1、Client发送请求以获取token,对应(A)(B),请求示范:
// 使用https发送以下请求: GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1 Host: server.example.com
2、认证服务器返回token,响应示范:
// "application/x-www-form-urlencoded" format HTTP/1.1 302 Found Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&state=xyz&token_type=example&expires_in=3600
返回的token在url的部分。
url格式:
[scheme:][//host:port][/path][?query][#fragment]
http://www.baidu.com:80/find?name=xxx&sex=nam#state=xxx
url的fragment以#号开头
密码模式
+----------+ | Resource | | Owner | | | +----------+ v | Resource Owner (A) Password Credentials | v +---------+ +---------------+ | |>--(B)---- Resource Owner ------->| | | | Password Credentials | Authorization | | Client | | Server | | |<--(C)---- Access Token ---------<| | | | (w/ Optional Refresh Token) | | +---------+ +---------------+
此模式第三方会获得到用主的用户名密码,适用于用户非常信任第三方的情况下。
1、请求令牌
POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=password&username=johndoe&password=A3ddj3w
2、返回令牌
HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache { "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "example_parameter":"example_value" }
客户端模式
+---------+ +---------------+ | | | | | |>--(A)- Client Authentication --->| Authorization | | Client | | Server | | |<--(B)---- Access Token ---------<| | | | | | +---------+ +---------------+
1、请求令牌
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
2、返回令牌
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"example_parameter":"example_value"
}
Client_id
授权服务器向注册的客户端颁发客户端标识符——唯一字符串。
协议端点(Protocol Endpoints)
两个授权服务器端点:授权端点、令牌端点
一个客户端端点:重定向端点
授权端点(Authorization endpoint):只适用于授权码模式和简化模式
令牌端点(Token Endpoint):第三方提交刷新token或用户授权到认证服务器此端点,以获取token
重定向端点(Redirection Endpoint):客户端重定向