OAuth 2.0认证-授权码模式的理解和实例分析

目前OAuth 2.0 认证有五种方式,见官方文档:http://www.rfcreader.com/#rfc6749

授权码模式(Authorization Code Grant)

流程图

OAuth 2.0认证-授权码模式的理解和实例分析

说明:
1,认证服务器是一个业务无关的系统;
2,code就是授权码,只能使用一次;
3,token 在有效期内可以无限次使用

场景化讲解-下单

场景:A 公司旗下有很多 web 产品,同时还有一个应用商店(类似京东)负责售卖这些软件产品,下面以用户进入应用商店购买产品的流程着手。

  1. 应用商店通过浏览器尝试获取下单页;
  2. 应用商店后台鉴权,发现没有登录(应用商店后台实际会调用认证服务器,比如校验 access tokensh是否有效);
  3. 跳转到登录页面;(对应上图(A))
  4. 用户通过浏览器输入用户名,密码等方式进行授权(此时会调用认证服务器接口);(对应上图(B))
  5. 认证服务器返回临时 code 给浏览器;(对应上图(C))
  6. 应用商店拿临时 code 去调用认证服务器接口,换取 access token;(对应上图(D))
  7. 认证服务器返回 access token给应用商店;(对应上图(E))
  8. 应用商店把 access token 缓存下来。
  9. 后续应用商店调用业务系统(比如下单接口,订单查询接口)接口均带上 access token;

场景化讲解-微信公众号授权

现在很多微商系统接入了微信公众号,通过微信公众号售卖产品,那么它们是如何获取用户信息的呢?
我们在关注某个商店性质的微信公众号时,经常会弹出如下对话框,要求我们授权
OAuth 2.0认证-授权码模式的理解和实例分析
图2-1
用户点击上述界面中的"允许",对应的操作是“"授权码模式"的(B)-- User authenticates:
OAuth 2.0认证-授权码模式的理解和实例分析

具体流程如下:

  1. 某微信公众号B 访问用户信息,用于下单支付(实际需要用户的 openid);
  2. 图2-1,微信弹框,要求用户授权;
  3. 用户点击"允许"授权,某微信公众号B才能获取到临时 code;
  4. 某微信公众号B拿临时 code调用微信鉴权接口获取 access token 或 openid;

实例3-对接钉钉通讯录实现登录

免登流程

第一步:通过用户授权获取code
授权链接:
https://h5.dingtalk.com/liveeasylogin/index.html#/index?appid=dingoae2vmockd44q2&response_type=code&scope=snsapi_auth&state=STATE&redirect_uri=http%3A%2F%2Flocalhost%3A7001%2Fapi%2Ftest%2FtestCode.json

第二步:用户授权
OAuth 2.0认证-授权码模式的理解和实例分析

授权成功获取code

{"content":"code=4d9954574c32afafd9xxx3c34b414aa&state=STATE","errorLevel":0,"success":true}

OAuth 2.0认证-授权码模式的理解和实例分析

code 值为:4d9954574c32afafd9xxx3c34b414aa

授权测试地址

dingtalk://dingtalkclient/page/link?url=https%3A%2F%2Fh5.dingtalk.com%2Fliveeasylogin%2Findex.html%23%2Findex%3Fappid%3Ddingoaemockdlfr66612%26response_type%3Dcode%26scope%3Dsnsapi_auth%26state%3DSTATE%26redirect_uri%3Dhttp%253A%252F%252Floca77host%253A7001%252Fapi%252Ftest%252FtestCode.json%3fddtab%3dtrue

code有什么用?

  1. 可以获取用户信息;
  2. 可以获取access_token

获取用户信息

//获取用户信息
DefaultDingTalkClient client = new DefaultDingTalkClient(DingTalkConstants.URL_GET_USER_INFO_BY_CODE);
OapiSnsGetuserinfoBycodeRequest request = new OapiSnsGetuserinfoBycodeRequest();
request.setTmpAuthCode(requestAuthCode);
request.setHttpMethod(HttpMethod.POST.toString());
OapiSnsGetuserinfoBycodeResponse response;
try {
response = client.execute(request, dingTalkProperties.getAppid(), dingTalkProperties.getAppsecret());
} catch (ApiException e) {
logger.error("accessToken:{0}, url:{1}", "", DingTalkConstants.URL_GET_USER_INFO_BY_CODE, e);
return null;
}
LoginedUser loginedUser = null;
if (response.isSuccess() && null != response.getUserInfo()) {
OapiSnsGetuserinfoBycodeResponse.UserInfo userInfo = response.getUserInfo();

获取access_token

参考

http://www.rfcreader.com/#rfc6749