都可以做 SSO
- CAS: 多个系统只需登录一次,无需重复登录
- oAuth: 第三方系统访问主系统资源,用户无需将在主系统的账号告知第三方,只需通过主系统的授权,第三方就可使用主系统的资源(如:APP1需使用微信支付,微信支付会提示用户是否授权,用户授权后,APP1就可使用微信支付功能了)
都可以做 SSO
oAuth 是一个关于授权的开放网络标准,目前 2.0 版。
oAuth 的作用就是让客户端安全可控地获取用户授权,与服务提供商互动
oAuth 在『客户端』与『服务提供商』之间,设置了一个授权层(authorization layer)。客户端不能直接登录『服务提供商』,只能登录授权层,这样将用户和『客户端』区分开。
『客户端』登录授权层后,『服务提供商』根据 token 的权限范围和有效期,向『客户端』开放用户存储的资料。
在人人网开放平台创建应用
得到 API KEY 和 Secret Key:
一定要填写回调:
用户使用 oAuth 是这个流程:
A. 用户打开客户端,客户端要求用户给授权
B. 用户同意授权给客户端
http://graph.renren.com/oauth/grant
* client_id=e9677ff99be74072ba2c59cd2dad944b
* redirect_uri=http%3A%2F%2Flocalhost%3A3333%2Fmain
* response_type=code
* display=page
* secure=true
* origin=00000
用户同意授权之后,页面会跳转到指定的回调地址。 这里我使用了
http://localhost:3333
本地地址,并且带上了『应用授权码』(code参数)
C. 客户端使用上一步得到的授权,向认证服务器申请 token
https://graph.renren.com/oauth/token
/*params*/
* grant_type=authorization_code
* client_id=e9677ff99be74072ba2c59cd2dad944b
* redirect_uri=http://localhost:3333/main
* client_secret=a3ab032aa239488abf081019b5fa2385
* code=vgHiJEY3Bc4GctffDNXQ1bu1TsUTZn98
把 code 和 secret key 一起发送申请token
这一步在客户端的后台服务器上完成,对用户不可见,这很重要!因为你的 secret key 是不能暴漏出来的!
D. 认证服务器对客户端进行认证后,确认无误,同意发放 token
E. 客户端使用 token,向资源服务器申请获取资源
使用 token 调用 API
F. 资源服务器确认 token 无误,同意向客户端开放资源
刚才说的人人网使用的就是授权码模式,这也是功能最完整、流程最严密的授权模式。特点是通过客户端的后台服务器,与"服务提供商"的认证服务器进行互动。
前端重定向到一个微信提供的地址:
login = () => {
location.href = `https://open.weixin.qq.com/connect/qrconnect?appid=${APP_ID}&redirect_uri=${encodeURIComponent('http://localhost:3000/api/wechat/callback')}&response_type=code&scope=snsapi_login&state=${Math.random()}#wechat_redirect`
}
然后到了这个页面,微信扫码登录:
扫码登录后跳转到 callback 页面:
router.get('/wechat/callback', async(ctx) => {
// code 是微信平台带过来的,需要用 code 申请 token
const { code } = ctx.request.query
// 申请 token
const res = await axios.get(`https://api.weixin.qq.com/sns/oauth2/access_token?appid=${APPID}&secret=${APPSECRET}&code=${code}&grant_type=authorization_code`)
const {
access_token,
refresh_token,
openid,
unionid,
} = res.data
// 有了 access_token 可以再去调用微信 API 获得头像等用户信息
// 略
// 这里把 openid 作为 cookie 带到前端,其实用 token 好一点
ctx.cookies.set('uid', openid)
ctx.response.redirect('/')
})
然后把 token 存在 redis 里,每次请求 cookie 里的 token 都会带上,验证是否合法,不合法则重新登录,略。