实战OAUTH 2.0授权机制

OAUTH 2.0简介

OAUTH 2.0是现在业界流行的认证授权方式,用户可以授权应用程序在不提供用户的密码的场景下,可以遵循OAUTH的规范来申请获取访问服务器的用户相关资源的权限。OAUTH 2.0的规范和流程还是比较难理解的,因此我用Keycloak来实际演示一下如何按照OAUTH 2.0的协议来进行授权。

OAUTH 2.0有以下四种授权方式:

Authorization Code

这种方式是最安全的,应用程序在用户登录认证成功后,授权服务器会返回一个code,应用程序需要用client_id和client secert以及这个code来换取一个token,这个token是由授权服务器进行签名后授予的一个凭证,里面包括了授权这个token的拥有者可以获得哪些资源的访问能力。应用程序拿到这个token后再和服务提供商请求获取服务。服务提供商拿到token进行校验,如果是授权服务器签发的,则授权通过。这种方式适合应用程序部署在服务器端的方式(server side application),因为可以在服务器端安全的保存client secret,即使code被第三方获取,也不能直接通过code来获得token。

Implicit

这种方式适合应用程序运行在客户端设备的方式(client side application),例如运行在客户手机的程序,或者web的java script等。因为在客户端设备无法安全的保存client secret,这种方式是直接申请获取token,而不是通过code的方式来间接获取。

Password

这种方式是直接以用户的用户名和密码来获取授权的token。这种方式只适合在用户高度信任应用程序的场景下,实际很少使用

Client Credential

这种方式是资源服务器是应用程序的一个后端模块,客户端向认证服务器提供client id和client secret来验证身份来获取令牌。

OAUTH 2.0演示

下面结合Keycloak来介绍一下authorization code, implicit, client credential这三种方式的认证授权流程。

  1. 进入keycloak管理界面,新建一个Realm, 命名为test
  2. 在test realm里面,在roles里面新建一个role,命名为API-VehicleData,代表后端提供了一个叫做vehicledata的API,可以读取用户的车辆信息。
  3. 在test realm里面,在client scope里面新建一个scope,命名为Scope-VehicleData,这个将出现在用户Consent的界面,代表用户是否同意应用程序获取其车辆数据。
  4. 在test realm里面,新建一个client,命名为My-App,这个代表了一个应用程序。在setting里面access type设置为confidential,打开Implicit Flow,valid redirect URI填入一个接收code或者token的地址,这里我先填入一个假地址例如http://www.example.com。在credential里面可以获取这个client的secret。在client scopes里面把刚才创建的API-VehicleData的role赋予到Assigned Default Client Scopes。在Scope里面设置Full Scope Allowed为off,然后加入刚才创建的Scope-VehicleData到assigned scope。
  5. 在test realm里面,新建一个user alice,这个用户将调用My-App来访问服务器端的vehicledata API来获取自己的车辆信息。

Keycloak的设置完成后,在test realm的realm setting->General->Endpoint->Openid endpoint configuration可以看到keycloak提供的各种endpoint,我们就可以调用keycloak的服务来进行演示了。

Authoriazion Code演示

  1. 获取code:在浏览器中打开http://192.168.1.107:8080/auth/realms/test/protocol/openid-connect/auth?response_type=code&client_id=My-App&redirect_uri=http://www.example.com, 用alice的用户名登录后,会有一个consent的页面,询问是否授权My-App使用Scope-VehicleData这个特权,授权完成后可以见到浏览器被重定向到了example.com,参数里面带了一个code,例如http://www.example.com/?session_state=fa5b9adb-a71b-4cc6-bcc7-5b1de2f899aa&code=c820ab0c-63db-4062-a236-87b2ee93890f.c47c9db3-f783-42b4-aeea-f4b88e4d58d7.8bf296ce-e2de-45bf-bce3-b377a5c05222
  2. 获取token:通过以下命令curl -d "client_secret=5160e3c2-9a02-4a59-aaf8-6f7af3aef1f9" -d "client_id=My-App" -d "grant_type=authorization_code" -d "code=c820ab0c-63db-4062-a236-87b2ee93890f.c47c9db3-f783-42b4-aeea-f4b88e4d58d7.8bf296ce-e2de-45bf-bce3-b377a5c05222" -d "redirect_uri=http://www.example.com" "http://192.168.1.107:8080/auth/realms/test/protocol/openid-connect/token", keycloak会返回一段json数据,其中的access_token是由3段组成,每段之间用.来分隔,第二段包括了赋予这个client的信息,我们可以用base64解码后查看内容
  3. 解码后的token第二段内容如下:{"jti":"41293d3c-f04f-40f7-84d5-ca8007f8f02b","exp":1581604011,"nbf":0,"iat":1581603711,"iss":"http://192.168.1.107:8080/auth/realms/test","sub":"43808ffc-2462-46cc-b342-7fde39289e9f","typ":"Bearer","azp":"My-App","auth_time":1581603659,"session_state":"c47c9db3-f783-42b4-aeea-f4b88e4d58d7","acr":"1","scope":"Scope-VehicleData"}, 可以看到有token过期时间,还有Scope-VehicleData, 以及sub中的用户alice的id
  4. My-App可以把这个token加到bearer中对后端的API进行访问,后端API可以通过Keycloak验证这个token,查询这个My-App是否具有API-VehicleData来调用这个API,并且根据token的第二段的内容来判断My-App是否有权限读取alice的车辆信息。

Implicit演示

  1. 获取token: 在浏览器中打开http://192.168.1.107:8080/auth/realms/test/protocol/openid-connect/auth?response_type=token&client_id=My-App&redirect_uri=http://www.example.com, 重定向后的URL里面带了token
  2. token的内容和校验方法如authorization code

client secret演示

  1. 在clients里面开启service account,然后执行命令curl -d "client_secret=5160e3c2-9a02-4a59-aaf8-6f7af3aef1f9" -d "client_id=My-App" -d "grant_type=client_credentials" "http://192.168.1.107:8080/auth/realms/test/protocol/openid-connect/token"

猜你喜欢

转载自blog.csdn.net/gzroy/article/details/104302140