天天看点

github接入三方登录vue+egg+ts(踩坑)

1.什么是三方登录?

三方登录就是通过第三方应用程序的账号密码, 快速的获取用户相关的信息实现登录

例如: QQ登录

点击QQ登录按钮之后,就会要求用户输入QQ的账号和密码

只要用户输入了QQ的账号和密码, 我们就可以拿到用户的QQ信息

我们就可以通过用户的QQ信息来实现注册登录

2.三方登录存在的问题

如果让用户在我们的网站上输入QQ的账号和密码,

那么我们就可以窃取用户的QQ号, 做一些见不得人的事

3.如何解决这个问题?

通过OAuth协议进行授权

4.什么是OAuth协议?(Open Authorization)

OAuth协议为用户资源的授权提供了一个安全的、开放而又简易的标准。

与以往的授权方式不同之处是OAuth的授权不会使第三方触及到用户的帐号信息(如用户名与密码),

即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,

因此OAuth是安全可靠的

5.OAuth授权流程

(1)第三方应用请求资源所有者(用户)授权。

(2)资源所有者同意给第三方应用授权。

(3)第三方应用使用步骤2中获得的授权,向授权服务器申请令牌。

(4)授权服务器对第三方应用进行认证并确认无误后,同意发放令牌。

(5)第三方应用使用步骤4中发放的令牌向资源服务器申请获取资源。

(6)资源服务器确认令牌无误后,向第三方应用开放资源访问。

OAth授权实现流程

(1)去到需要接入的网站申请接入

例如: 要实现Github登录, 就去到Github申请接入

https://github.com/settings/applications/new

github接入三方登录vue+egg+ts(踩坑)

注意上图有误:回调url应该是请求的后端服务器,而不是前端服务器

(2)申请完接入之后会得到一个Id和Secret

例如: 申请完Github登录, 我们会得到

Client ID:xxx

Client Secret:xxxx

(3)在自己的网站放上对应的第三方登录按钮

<li class="iconfont icon-github" style="color: #000">
          <a href="http://127.0.0.1:7001/github"></a>
  </li>
           

(4)当用户点击登录按钮之后, 按照文档要求带着申请到的id获取登录界面,为什么要带id, 因为需要知道是你有没有接入权限,因为要告诉用户是给谁授权

https://docs.github.com/en/developers/apps/authorizing-oauth-apps

照着官方文档的web application flow的步骤来做;

(5)当用户点击授权按钮之后, 会跳转我们之前设定好的回调页面去,并且返回一个code给我们,这个code就是用户同意授权的临时证据

(6)我们拿着这个临时证据(code)去到授权服务器换取长久令牌,授权服务器会验证用户是否真的同意, 如果同意会返回一个access_token给我们,这个access_token就是长久令牌

(7)我们拿着长久的令牌去到资源服务器获取授权用户相关的资源

//router.ts

router.get('/github', controller.github.loginView);
router.get('/github/callback', controller.github.getAccessToken);
           

//controller/github.ts

import { Controller } from 'egg';
const queryString = require('querystring');

export default class GithubController extends Controller {
    public async loginView() {
        // 1.获取第三方登录界面
        // 发送get请求到https://github.com/login/oauth/authorize带上一些参数即可
        // client_id: Github可以根据这个client_id判断你有没有申请接入
        //            Github会根据这个client_id查询出对应的应用程序名称, 告诉用户正在给哪个程序授权
        // scope    : 授权范围
        const baseURL = 'https://github.com/login/oauth/authorize';
        const option = {
            client_id: 'xxx',
            scope: 'user'
        }
        const url = baseURL + '?' + queryString.stringify(option);
        const {ctx} = this;
        //这个页面是用户进行授权的页面
        ctx.redirect(url);
    }
    //上一步用户授权登陆完成后,会返回code,请求的是我们之前在github上设定好的回调地址
    public async getAccessToken(){
        const {ctx} = this;
        // 1.拿到用户同意授权之后的code
        const {code} = ctx.query;
        // 2.利用code换取令牌(access_token)
        // 发送POST请求到https://github.com/login/oauth/access_token带上必要的参数
        const baseURL = 'https://github.com/login/oauth/access_token';
        const option = {
            client_id:'xxx',
            client_secret:'xxxxx',
            code:code
        }
        const result = await ctx.curl(baseURL, {
            method: 'POST',
            data: option,
            dataType: 'json',
            headers:{
                'Content-Type': 'application/json',
                'Accept':'application/json'
            }
        });
        const accessToken = result.data.access_token;

        console.log("accessToken",accessToken)
        // 3.拿着令牌去资源服务器获取数据
      await  this.getGithubUserInfo(accessToken);
    }
    //获取用户数据
    private async getGithubUserInfo(accessToken){
        const {ctx} = this;
        const baseURL = 'https://api.github.com/user';
        const url = `${baseURL}?access_token=${accessToken}`;
        const result = await ctx.curl(url, {
            method: 'GET',
            headers:{
                Authorization:"token "+accessToken
            }
        });
        console.log("here",JSON.parse(result.data));
        ctx.body="hello"
        //坑:我们希望用户界面跳转github回调地址的时候,不要显示404 not found,而是显示hello,那么首先因为这个是异步的方法,所以调用this.getGithubUserInfo()的前面要加上await,另外,在执行所有路由对应的方法前,都要先执行中间件方法,那么中间件next()的时候前面也要await,不然就没等异步方法走完,就结束了,就相当于没有处理
    }
}

           

如何反复测试

选择浏览器的清除历史记录,这样就能够反复测试用户授权功能了