欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

OAuth 2.0 通过第三方账号来登录自己的网站

程序员文章站 2023-12-31 20:54:58
OAuth 2.0 基本概念OAuth 2.0 是目前最流行的授权机制,用来授权第三方应用,获取用户数据。 例如这是我开发的网站 http://edraw.top/,你并没有在我的网站上注册过账号,但是你可以通过 QQ 来登录我的网站,登录之后,我的网站也可以获取到你的 QQ 昵称和头像。 假如你自己做了一个网站,也懒得做注册和登录模块,那你不妨像我一样,利用 OAuth 2.0 接入这些知名的站点,让他们的账号信息为我所用。开发环境我的网站后端是用 nodejs 写的,用的是 eggjs,实际的授权...

OAuth 2.0 基本概念

OAuth 2.0 是目前最流行的授权机制,用来授权第三方应用,获取用户数据。 例如这是我开发的网站 http://edraw.top/,你并没有在我的网站上注册过账号,但是你可以通过 QQ 来登录我的网站,登录之后,我的网站也可以获取到你的 QQ 昵称和头像。 假如你自己做了一个网站,也懒得做注册和登录模块,那你不妨像我一样,利用 OAuth 2.0 接入这些知名的站点,让他们的账号信息为我所用。

开发环境

我的网站后端是用 nodejs 写的,用的是 eggjs,实际的授权调用也都是在 node 端完成的。其他后端语言同理,下面是大致的流程图
OAuth 2.0 通过第三方账号来登录自己的网站
流程分为 12 个步骤,以 github 授权为例:

  • 浏览器端点击 github 小图标,请求服务端 /auth/github 接口;
  • 服务端返回 302 重定向标志给前端,重定向的地址为:https://github.com/login/oauth/authorize?responsetype=code&redirecturi={应用回跳地址假设 A.com}&client_id={github 分配的应用唯一标识};
  • 浏览器收到 302 标志后,跳转到上述地址;
  • github 收到请求后,根据 client_id,为应用生成一个 code,我们称之为授权码。并且重定向到 http://A.com?code=xxx;
  • 前端拿到授权码 code 后,向后端请求令牌 access_token;
  • 后端接受到请求后,向 github 请求 accesstoken,请求参数为 code(授权码)、clientid(应用标识)、client_secret(应用秘钥);
  • github 返回 access_token,及有效时间;
  • 后端接收到 access_token 后将其写入 cookie,并返回给前端;
  • 前端拿到 access_token 后,请求用户信息;
  • 后端接收到请求后,去 github 上请求用户信息,参数是 access_token;
  • github 返回用户信息 ;
  • 后端将用户信息返回到前端。 因为 accesstoken 被写进了 cookie,前端所有的请求都会带上 accesstoken,后端就可以根据 cookie 中的令牌来验证用户身份。 每家站点的接入流程基本一致,QQ 会多一个步骤,所以放在最后讲。

关键术语定义

  • 平台:需要接入的网站,如 QQ、微博、Github、百度;
  • code:授权码,由平台返回;
  • clientid:应用标识,在平台上创建应用后,由平台分配;
  • clientsecret:应用秘钥,在平台上创建应用后,由平台分配;
  • 回跳地址:第 3 步重定向到平台后,平台生成 code 后需要重定向到你的网站,这个重定向的地址就是回跳地址;

接入百度账号

  1. 登录百度开发者中心

  2. 拉到底部,注册成为“百度开发者”;
    OAuth 2.0 通过第三方账号来登录自己的网站

  3. 注册成功之后创建工程

  4. 按步骤创建成功之后,平台会为你的网站分配 API Key(前文提到的 clientid)、Secret Key(前文提到的 clientsecret)

  5. 将申请到的 clientid、clientsecret 保存到项目中

// 这是我的配置
config.passport_baidu = {
    key: 'xxxxxx',
    secret: 'xxxxxx',
    authorize_url: 'https://openapi.baidu.com/oauth/2.0/authorize',  // 第 2 步,后端返回的 302 重定向地址
    api_token: 'https://openapi.baidu.com/oauth/2.0/token',  // 第 6 步,后端请求 access_token 地址
    api_user: 'https://openapi.baidu.com/rest/2.0/passport/users/getInfo', // 第 10 步,后端请求用户信息地址
    get_token_method: 'POST' // 获取 access_token 的方法
  };

将上诉配置带入到开始的流程图中即可完成百度账号授权登录。具体效果可参考我的网站
OAuth 2.0 通过第三方账号来登录自己的网站

接入 Github

  1. 打开 github,头像 Setting > 左侧 Developer setting > 左侧 OAuth Apps
  2. 点击右侧 New OAuth App
  3. 输入应用名称、首页地址、回跳地址等信息
  4. 完成应用新建之后,平台会分配相应的 Client ID(前文提到的 clientid)、Client secrets(前文提到的 clientsecret)
  5. 将申请到的 clientid、clientsecret 保存到项目中
// 这是我的配置
  config.passport_github = {
    key: 'xxxxxxx',
    secret: 'xxxxxxx',
    authorize_url: 'https://github.com/login/oauth/authorize',  // 第 2 步,后端返回的 302 重定向地址
    api_token: 'https://github.com/login/oauth/access_token',  // 第 6 步,后端请求 access_token 地址
    api_user: 'https://api.github.com/user', // 第 10 步,后端请求用户信息地址
    get_token_method: 'POST' // 获取 access_token 的方法
  };

将上诉配置带入到开始的流程图中即可完成github账号授权登录。具体效果可参考我的网站
OAuth 2.0 通过第三方账号来登录自己的网站

接入微博

  1. 打开 https://open.weibo.com/connect,创建应用;
  2. 按步骤填写信息;
  3. 完成应用新建之后,平台会分配相应的 App Key(前文提到的 clientid)、App Secret(前文提到的 clientsecret);
  4. 将申请到的 clientid、clientsecret 保存到项目中。
// 这是我的配置
  config.passport_github = {
    key: 'xxxxxxx',
    secret: 'xxxxxxx',
    authorize_url: 'https://api.weibo.com/oauth2/authorize',  // 第 2 步,后端返回的 302 重定向地址
    api_token: 'https://api.weibo.com/oauth2/access_token',  // 第 6 步,后端请求 access_token 地址
    api_user: 'https://api.weibo.com/2/users/show.json', // 第 10 步,后端请求用户信息地址
    get_token_method: 'POST' // 获取 access_token 的方法
  };

将上诉配置带入到开始的流程图中即可完成微博账号授权登录。具体效果可参考我的网站
OAuth 2.0 通过第三方账号来登录自己的网站

接入 QQ

QQ 比较坑的地方是,你的网站必须先备案,拿到备案信息之后,创建应用才能审核通过

  1. 打开 QQ 互联 https://connect.qq.com/manage.html#/;
  2. 创建网站应用;
  3. 填入网站基本信息和备案等信息,备案信息的每个字段切记要认真核对,错一个字都会审核不通过,我在这一步反反复复卡了有一个月;
  4. 审核通过之后,将申请到的 APP ID(clientid)、APP Key(clientsecret )保存到项目中。
// 这是我的配置
  config.passport_github = {
    key: 'xxxxxxx',
    secret: 'xxxxxxx',
    authorize_url: 'https://graph.qq.com/oauth2.0/authorize',  // 第 2 步,后端返回的 302 重定向地址
    api_token: 'https://graph.qq.com/oauth2.0/token',  // 第 6 步,后端请求 access_token 地址
    api_openid: 'https://graph.qq.com/oauth2.0/me',  // QQ 会多一步获取 openid,获取用户信息需要用到 openid
    api_user: 'https://graph.qq.com/user/get_user_info', // 第 10 步,后端请求用户信息地址
    get_token_method: 'GET' // 获取 access_token 的方法
  };

QQ 获取到 access_token 之后,需要再获取 openid 之后再去获取用户信息

关键方法

下面是授权过程中主要用到的 3 个方法,在这里贴出来供大家参考 获取 access_token

async getToken(param) {
    const { app, ctx } = this;
    const config = app.config['passport_' + ctx.session.loginType];
    const res = await app.curl(config.api_token, {
      method: config.get_token_method || "POST",
      dataType: "json",
      data: {
        grant_type: 'authorization_code',
        code: param.code,
        client_id: config.key,
        client_secret: config.secret,
        redirect_uri: 'http://edraw.top/personal/file',
        fmt: 'json'
      },
    });
    if (res.status === 200 && res.res.data) {
      const { access_token, uid } = res.res.data;
      ctx.session.token = access_token;
      ctx.session.uid = uid;
      ctx.cookies.set("cookie-user-token", access_token, {
        httpOnly: false
      });

      if (ctx.session.loginType === 'qq') {
        await this.getOpenId(access_token, config.api_openid);
      }

      return {
        data: access_token,
      };
    }
    return {
      success: false,
      message: "授权码已失效,请重新登陆",
    };
  }

获取 openid(只有 qq 登录会用到)

async getOpenId(token, url) {
    const { app, ctx } = this;
    const config = app.config['passport_' + ctx.session.loginType];
    const res = await app.curl(url, {
      method: "GET",
      dataType: "json",
      data: {
        access_token: token,
        fmt: 'json'
      },
    });
    if (res.status === 200 && res.res.data) {
      const { client_id, openid } = res.res.data;
      ctx.session.openid = openid;
      ctx.session.client_id = client_id;
      return {
        data: openid,
      };
    }
    return {
      success: false,
      message: "授权码已失效,请重新登陆",
    };
  }

获取用户信息

async getUserInfo(param) {
    const { app, ctx } = this;
    const config = app.config['passport_' + ctx.session.loginType];
    const res = await app.curl(
      config.api_user,
      {
        method: "GET",
        dataType: "json",
        data: {
          access_token: ctx.session.token,
          openid: ctx.session.openid,
          oauth_consumer_key: ctx.session.client_id,
          uid: ctx.session.uid
        },
      }
    );
    if (res.status === 200 && res.res.data) {
      const userInfo = ParseUser['parse_' + ctx.session.loginType](res.res.data);
      ctx.session.user_name = userInfo.user_name;    // 昵称
      ctx.session.avatar_url = userInfo.avatar_url;  // 头像
      this.addUser(userInfo);
      return {
        data: userInfo,
      };
    }
    return {
      code: 10001,
      success: false,
      message: "获取用户信息失败,请重新登陆",
    };
  }

请求的参数并不是每家站点都一样,我只是把这几家用到的参数都晒进去了,多了没事,少了却不行。 全文到此结束,希望能给读者带来帮助。

本文地址:https://blog.csdn.net/qq_28773159/article/details/112574985

上一篇:

下一篇: