今天我们来讲解一下OAuth2,在平时应用中我们经常能够见到它的身影。比如,当微信小程序获取你的用户名和头像时需要你授予权限,以及当我们在网站上使用微信或QQ登录时也是使用到了OAuth2。接下来我们便来讲解一下OAuth2。
OAuth 2.0是目前最流行的授权机制,用来授权第三方应用,获取用户数据。
OAuth(开放授权)是一个关于授权的开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息(比如照片、视频、用户信息等),而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容,OAuth2.0是OAuth协议的延续版本,但不向后兼容OAuth 1.0。即完全废止了OAuth1.0。OAuth 2.0协议正式发布为RFC-6749。
OAuth2主要包含以下特点:
用于REST/APIs的代理授权 框架(delegated authorization framework)
基于令牌Token的授权, 在无需暴露用户密码的情 况下,使应用能获取对用 户数据的有限访问权限
解耦认证和授权
事实上的标准安全框架,支持多种用例场景
在常规情况下应用请求资源服务器, 访问客户数据,在没有OAuth2的情况下,资源服务器区分不出请求过来的应用是恶意用户还是其他用户,数据都会返回。 如下图所示:
因此为了用户安全访问数据,在访问中间添加了Access Token机制。客户端需要携带Access Token去访问受到保护的资源。
OAuth2就是让我们使用授权服务器颁发给客户应用Access Token。
最后客户端拿到Access Token去资源服务器进行校验,验证通过之后才返回数据。
OAuth2的整体流程图如下:
简单说就是:客户应用向授权服务器请求Access Token —> 授权服务器向用户征询意见,是否将权限授予客户应用 —> 用户同意 —> 授权服务器生成颁发Access Token给客户应用 —> 客户应用拿着Access Token去请求资源服务器 —> 资源服务器验证客户应用的Access Token —> 验证通过,返回数据
在OAuth2中主要有四个角色,主要如下:
OAuth2中的其他术语:
OAuth2中的令牌类型:
通过上面的介绍我们大概总结如下:
从运行流程不难看出,要获取access token必须先得到用户授权(authorzation grant),那么如果获取这么用户授权呢?OAuth 2.0定义了四种类型的授权类型
授权码模式是功能最完整、使用最广泛、流程最严密的授权模式。
授权码(authorization code)方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌。
第一步:用户访问客户端,客户端将用户导向授权服务器,通过用户代理(User-Agent)发送包括它的客户端标识符、请求的范围、本地状态和一个重定向URI,授权服务器在授予(或拒绝)访问权后将其发送给用户代理。URI如下:
http://localhost:8080/oauth/authorize?client_id=clientapp&redirect_uri=http://localhost:9001/callback&response_type=code&scope=read_userinfo
在URI中response_type参数表示要求返回授权码(code),client_id参数让授权服务器知道是谁在请求,redirect_uri参数是授权服务器接受或拒绝请求后的跳转网址,scope参数表示要求的授权范围(这里是只读)。
第二步:授权服务器对资源所有者进行身份验证(通过用户代理,让用户输入用户名和密码),并确定资源所有者是否授予或拒绝客户端的访问请求。
第三步:用户跳转后,假如资源所有者同意授权请求,那么授权服务器将会使用前面提供的或者事先指定的重定向URI(redirection URI),重定向到客户端,并附上一个授权码(code)和一个前面提供的本地状态(state)(如果有的话,则会原值返回)。
http://localhost:9001/callback?code=ghN0hf
第四步:客户端收到授权码,附上早先的重定向URI,向授权服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。在发出请求时,授权服务器对客户端进行身份验证。请求参数包含授权代码、用于获得验证的授权代码的重定向URI、标识客户端身份的client id和client secret。
http://localhost:8080/oauth/token?client_id=clientapp&client_secret=123&code=ghN0hF&grant_type=authorization_code&redirect_uri=http://localhost:9001/callback&scope=read_userinfo
注意:用户密匙和密码可以在headers里添加认证,Authorization。
上面 URL 中,client_id参数和client_secret参数用来让授权服务器确认客户端的身份(client_secret参数是保密的,因此只能在后端发请求),grant_type参数的值是authorization_code,表示采用的授权方式是授权码,code参数是上一步拿到的授权码,redirect_uri参数是令牌颁发后的回调网址。
第五步:授权服务器对客户端进行身份验证,验证授权代码,并确保所收到的重定向URI与用于在步骤©中对客户端重定向的URI相匹配,如果有效,授权服务器将发送访问令牌access token和刷新令牌refresh token(可选)。
然后授权服务器给我们返回授权码,如下:
{
"access_token": "36cded80-b6f5-43b7-bdfc-594788a24530",
"token_type": "bearer",
"expires_in": 43199,
"refresh_token":"45cdce99-b6f5-8866-bdfc-764745a45780",
"scope": "read_userinfo"
}
这里的参数主要是:
最后我们拿到access_token去访问受保护的资源即可,如下:
http://localhost:8080/api/userinfo?access_token=f4345f3a-34a3-4887-bc02-e95150c54bf4
简化模式(implicit grant type)不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了"授权码"这个步骤,因此得名。所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。
第一步:用户访问客户端,客户端将用户导向授权服务器,通过用户代理(User-Agent)发送包括它的客户端标识符、请求的范围、本地状态和一个重定向URI,授权服务器在授予(或拒绝)访问权后将其发送给用户代理。URI如下:
http://localhost:8080/oauth/authorize?client_id=clientapp&redirect_uri=http://localhost:9001/callback&response_type=token&scope=admin&state=abc
这一步为直接申请授权token,参数和申请授权码类似,client_id,redirect_uri回调地址,response_type有变动,改为直接获取token,scope权限,state用于认证标记,传过去什么回调时传回来什么。
第二步:授权服务器对资源所有者进行身份验证(通过用户代理,让用户输入用户名和密码),并确定资源所有者是否授予或拒绝客户端的访问请求。
第三步:用户跳转后,假如资源所有者同意授权请求,那么授权服务器将会使用前面提供的或者事先指定的重定向URI(redirection URI),重定向到客户端,并附上访问令牌等信息。如下:
http://localhost:9001/callback#access_token=0406040a-779e-4b5e-adf1-bf2f02031e83&token_type=bearer&state=abc&expires_in=119
同理,我们拿到access_token就可以访问受保护的资源了。
http://localhost:8080/api/userinfo?access_token=0406040a-779e-4b5e-adf1-bf2f02031e83
密码模式中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向"服务商提供商"索要授权。
在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。
第一步:用户访问客户端,客户端将用户导向授权服务器,然后提供URI连接包含用户名和密码信息给授权服务器。如下:
http://localhost:8080/oauth/token?client_id=clientapp&client_secret=123&username=anumbrella&password=123456&grant_type=password&scope=admin
注意:用户密匙和密码(client_id和client_secret)可以在headers里添加认证,Authorization。
第二步:授权服务器认证用户名和密码信息正确后,然后返回客户端access_token等信息,如下:
{
"access_token": "58a02fd5-87f5-44ff-bbdd-d429cf6a2f60",
"refresh_token":"45cdce99-b6f5-8866-bdfc-dtfsdft55780",
"token_type": "bearer",
"expires_in": 43199,
"scope": "admin"
}
同理,拿到access_token即可访问我们需要访问的资源。
客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向"服务提供商"进行认证。严格地说,客户端模式并不属于OAuth框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求"服务提供商"提供服务,其实不存在授权问题。
第一步:客户端直接向授权服务器发起认证请求,URI如下:
http://localhost:8080/oauth/token?client_id=clientapp&client_secret=123&grant_type=client_credentials&scope=admin
注意:用户密匙和密码(client_id和client_secret)也可以在headers里添加认证,Authorization。
第二步:授权服务器通过认证后,直接返回客户端access_token等信息,如下:
{
"access_token": "776b162a-949e-4dcb-b16b-9985e8171dc0",
"refresh_token":"46ffdtfa-b6f5-8866-bdfc-dtfsdft55780",
"token_type": "bearer",
"expires_in": 43188,
"scope": "devops"
}
最后我们拿到access_token即可访问相关资源。
好了,OAuth2相关基本概念就到这里了,后面再介绍相关实战知识,请持续关注。最近换工作了,所以时间比较紧,博客更新有点点慢,后面我会多抽时候把计划的相关体系的知识点都保量保质更新起走,欢迎大家关注!!