# Token
现在正在开发一个信用卡管家的APP,可以从邮箱里面读邮件,汇总形成报表 。
但是这个程序需要读网易邮箱,需要用户名和密码,用户并不信任这个小网站
但是如果不用用户名和密码,又怎么登录呢?
可以提供一个**新的入口**,使用网易账号登录,点进去了以后,实际上会**重定向**到网易的认证系统中去。
网易的认证系统会让用户输入用户名和密码,并且询问是否允许信用卡管家访问网易邮箱。
如果用户确认了,就会重定向到信用卡管家的网站上,同时会带来一个token。
信用卡管家网站就可以使用token来访问网易邮箱了。
这样,整个过程中,信用卡管家网站不会接触到用户名和密码。
那么网易怎么知道是信用卡管家这个网站在申请授权呢?
首先信用卡管家需要在网易上注册一下,然后网易会颁发一个app_id和app_secret。
当用户点击第三方登陆的时候,会把app_id和app_secret传过去,这样网易就知道是‘信用卡管家’这个应用在申请授权了。
下图为流程:
![image.png](http://upload-images.jianshu.io/upload_images/1323506-637f18cbc17f79a3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 浏览器点击进去的时候,信用卡管家会返回给浏览器一个URL,里面包含了app_id,链接为 `www.163.com/xxxx?appid=xxx&return_uri=https://www.a.com/callback`
首先访问的是`www.163.com`,然后携带了`appid`,然后告诉网易认证中心,认证成功以后的还需要跳转到我自己的网站上,也就是return_uri,它的意思是,如果认证成功了以后,会回转到信用卡管家`https://www.a.com/callback`这个页面来
- 浏览器重定向到网易认证中心,同时携带了app_id。也就是告诉网易,是信用卡管家这个应用在寻求授权。
由网易认证中心的返回它的登录界面。
- 用户使用网易账号登录,同时点击同意授权给信用卡管家。
网易认证中心会返回一个token,这个token是嵌在`https://www.a.com/callback#token=<生成的token>`里面的。
- 然后浏览器访问`https://www.a.com/callback#token=<生成的token>`,目的是把token传给信用卡管家,以便于它继续用这个token 来访问网易邮箱了
- 浏览器自己也会把token取出来。
可以看出整个流程里面用户名和密码都没有经过信用卡管家,它能拿到的就只是token而已。
为什么我们要用JavaScript去读取token啊?
这样后端服务器就不用参与了,少了很多交互的过程。工作都可以终止于前端。
我们可以再看一下这个链接`https://www.a.com/callback#token=<生成的token>`,里面的#号就叫hash fragment,它只会停留在浏览器端,只有Javascript才能访问它,而且不会通过HTTP请求发到其他服务器上,可以提高安全性。
但是问题又来了,这个token是以明文的形式发到浏览器的,虽然是HTTPS的,但是如果浏览器的历史记录或者访问日志被盗了怎么办,一样能拿到。
# Authorization Code + Token
上面我们说了,token是明文传递的,虽然传播的路径是加密的(HTTPS),但是在浏览器本地存储中依然可以找到。
那么我们可以引入应该 Authorization Code的中间层。
当用网易账号登录的时候,网易认证中心返回的是一个授权码(authorization code)而不是token。
那么信用卡管家服务器端取到这个code以后,还需要在后台再次访问网易认证中心,然后才可以得到真正的token
![image.png](http://upload-images.jianshu.io/upload_images/1323506-abcd8c2515841a73.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 前5个步骤都一样,无非是浏览器先从信用卡管家的服务器端拿到app_id,然后传递给网易,由网易弹出登录界面,进行登录
区别是,网易返回的是code而不是token,`https://www.a.com/callback?code=3679`
- 浏览器依旧会把code传给信用卡管家的服务器,由它向网易申请token,`https://www.163.com/xxx?appid=xxx&secret=xxxx&code=3679&return_uri=https://www.a.com/callback`,需要把appid和returl_uri传递过去的原因是之前都出浏览器传的,而现在信用卡管家自己把自己当做另一个浏览器而已。
- 网易回复一个token,`https://www.a.com/callback?token=6789`
还是与之前同样的问题,code依然是明文的,可以在浏览器记录里面找到。
可以这样,比如让授权码与app_id,app_secret相关联,也就是通过他们运算出来,这样,只有信用卡管家服务器发出的token请求才合法。
也可以让授权码有时间限制,比如说过一段时间失效,这样,一个授权码只能换一次token。
本文所述的其实就是OAuth的三种认证方式: