最近又去忙活了微信的网页授权(用的oauth2.0授权标准),真是烧死了我不少脑细胞啊。花点时间整理一下对oauth2.0授权这玩意理解,以后说不定会用得到。对这东西的理解不深刻,要真正理解这玩意还是得完文档oauth官网,这里找一种自己能理解的方式。
授权逻辑上要解决的问题
忘记关于授权的一切,从零开始吧,
本来用户和资源服务器之间进行交互式没有任何问题的,比如,qq,我们的资源(个人信息、头像之类)也都存在腾讯的服务器上,我们提供账号和密码就可以登录了,qq客户端和腾讯的服务器进行交互,根本不会涉及到第三方,也就不会涉及到授权问题了。现在第三方为用户提供服务的时候或者说基于某些目的,需要使用用户的资源,需要用户的授权,要解决以下问题:
1. 资源服务器信任第三方网站(当然了其他应用程序app啥的也行,肯定是包含第三方的客户端和服务器的啦),这样资源服务器才有可能响应第三方网站的请求;
2. 用户同意资源服务器给第三方网站自己的资源,这就要求资源服务器在给第三方网站之前用户的资源之前,必须先征求用户的同意。
3. 还没想到。。。
画个简单的图就理清楚上述关系了:
对上述流程图,我们需要注意几个点:
1、对于资源服务器而言,要确定第三方网站可信,并且对于用户的资源的访问权限要做细致的划分和管理;
2、对于用户来说,资源服务器认为第三方网站可信时,将第三方的资料和资源服务器将要授权的用户的资源呈现给用户;
3、用户决定是否授权或者授权的类型决定了第三方网站能访问用户的哪些资源;
最后,,,说白了授权就是第三方请求资源服务器获取资源,资源服务器信任第三方以后,资源服务器在询问用户是否同意授权(用户看得到第三方资料和将要授权的资源)。还有两个问题:资源服务器并不能访问用户啊,,,该肿么办呢?愁死宝宝了。。。
增加用户代理实现授权流程
分析清楚了授权的逻辑以后,接下来就是实现过程了。
1、资源服务器信任第三方应用程序,最简单的方式莫过于第三方在资源服务器的平台下注册成为合法的应用。这样当第三方访问资源服务器的时候,是吧,这个应用是合法的。。。。。。
2、增加用户代理(在这里的话也就是所谓的浏览器啦),这样用户和资源服务器之间就可以通过代理进行交流信息了,上图:
注意到了吗?我们这里已经把上面的第三方网站或者应用拆分成用户代理和第三方服务器两部分了,这个不奇怪吧?
3、http协议是被动协议啊,上图的步骤c怎么可能执行呢???究竟怎么办呢???c是执行不了了,看来。仔细分析一下途中的各个步骤,B步骤的目的在于向资源服务器申请资源,这个也可以用用户代理来实现,,,恰好在这一步之中顺便携带c步骤,,,很完美啊。
站在用户的角度,其实步骤3之中涉及到的东西可不就是重定向吗?java servlet之中一个servlet玩不成的任务让两个servlet来完成就行了。放在这里只不过相当于是两个服务器上的两个路由,下面分别是最终的时序图和流程图:(省略了用户授权以后资源服务器返回结果,就是个重定向,定向到第三方服务器在B步骤之中指定的回调页面了)
4、这里最后还剩下一个问题,就是用户授权以后第三方服务器怎么获取用户信息的问题。用户授权以后会浏览器会访问第三方服务器指定的重定向url(什么时候指定的呢?序列图中的redirectUrl指定的),这个url附带了code参数,,,第三方服务器获取这个code参数加上其他的一些参数换取accesstoken,利用accesstoken就可以获取用户信息了。
这里附上一些资源,,,
阮一峰 理解OAuth 2.0(没看懂,,,很尴尬);
oauth官网;
写到这里基本就算完结了,还有很多方面没有写到,,,碎觉。。。以后再说。。。算了,先不睡,还是附上微信登录网页授权的demo吧。
node实现微信网页授权
微信网页授权思路是在后台增加一个路由拦截器,内容如下,
const request = require('request');
let redirect_url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect`;
let accsess_token_url = `https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code`;
let user_info_url = `https://api.weixin.qq.com/sns/userinfo?access_token=${access_token}&openid=OPENID&lang=zh_CN`;
async function(ctx,next){
//两个作用,判断用户是否授权过,决定跟新用户信息的频率
if(ctx.session.user){
return await next;
}else if(ctx.query.code){
//通过code换取access_token;
let access_token = await request(accsess_token_url);
// todo 对await返回结果提取出accsess_token来
let user_info = await request(user_info_url);
//todo 处理userinfo,保存信息 ,存到session
let this.session.user = user_info;
return await next;
}else{
return ctx.redirect(redirect_url);
}
}
}
对于第三方应用的开发来说,用户授权相当于一个状态机,三种状态,已授权,已获取code,还未获取code,需要对这三种情况进行处理。我感觉应该有很优雅的方式来实现上述代码,因为执行的代码就相当于有三个步骤,三种状态分别对应:123 23 3 这样的步骤,,,暂时没想到,也不想去想了。。。