最简洁实现Github登录的JS代码示例

本文来自于公众号链接: 最简洁实现Github登录的JS代码示例
公众号中文章格式更加良好,图片不丢失。

本文源码地址: https://github.com/Spring-Security-China/oauth2-client-login-js-github

大纲

  • 概述
  • 实现思路分析
  • 在Github官网注册OAuth2应用
  • 代码实现
  • 运行与演示
  • 总结

概述

本来希望使用纯前端的方式,只一个html在浏览器中运行,最简洁地就能实现Github登录。但是理想很丰满,现实很骨感,实际上需要前端和后端相互配合才可以。

Github的第三方登录功能背后的技术实际上是OAuth2协议,OAuth2协议本身有一定的复杂性,简单理解的话,可以参考公众号文章《OAuth2核心协议概览》

图片[]

我们知道OAuth2协议中有OAuth2的授权服务器、资源服务器、OAuth2客户端和用户代理这四个角色主体。与其他很多互联网平台如微信公众平台、Google、OKTA等等一样,Github同时是OAuth2授权服务器和资源服务器。用户代理是指的浏览器。那么本文写的代码示例,实际上就是一个OAuth2客户端。

本文希望不需要了解OAuth2协议的细节,仅仅通几行js代码,就可以实现接入Github登录。从而可以先直观地感受下OAuth2核心协议。

实现思路分析

如何接入Github登录?看官网:https://developer.github.com/apps/building-oauth-apps 获取token需要两个步骤:

  1. 获取code:浏览器访问 https://github.com/login/oauth/authorize 同时传递回调地址等参数
  2. 使用code获取token:接收到code后,发起POST请求调用 https://github.com/login/oauth/access_token

感觉很简单,那我们直接写个html页面,在页面中写两个方法不就解决了?类似这样:

functionn getCode(){
    window.location.href = "https://github.com/login/oauth/authorize"+...
}
function getToken(code){
    ...POST "https://github.com/login/oauth/access_token" 获取token...
}

这种方案行不通,首先因为“/oauth/access_token”接口是不允许跨源访问的,关于什么是跨源,可以参考《彻底理解浏览器同源策略SOP》《彻底掌握CORS跨源资源共享》两篇文章。也就是说浏览器无法调用这个接口。其次,如果浏览器可以调用这个接口获取token,那么意味着token暴露在了浏览器端,增加了token泄露的风险。实际上根据OAuth2协议来看,通过code交换token的这个接口流程属于后端流程(“back-end flow”),是后端调用的。

那么只好增加复杂性,引入后端,实现一个前端+后端的最简洁的Github登录的JS代码示例。

图:[silu.png]

在Github官网注册OAuth2应用

首先需要在Github官网注册一个新的OAuth2应用,地址是:https://github.com/settings/applications/new

image

  1. Application Name:必填,应用名称, 设置为:oauth2-client-login-js-github
  2. Homepage URL: 必填,应用主页,设置为http://localhost:8080
  3. Application description: 选填,应用的说明,置空即可。
  4. Authorization callback URL: 必填,OAuth认证的重定向地址,本地开发环节可设置为http://localhost:8080

当用户通过浏览器成功登录Github,并且用户在批准页(Approva Page)授权允许注册的客户端应用访问自己的用户数据后,Github会将授权码(code)通过重定向方式传递给客户端应用。

填写无误后,点击Register appcation 按钮,注册成功后,获取到clientIdclientSecret

代码实现

源码地址: https://github.com/Spring-Security-China/oauth2-client-login-js-github
插图:jiegou.png

  • server.js是nodejs实现的后端
  • loginGithub.html是普通html模拟前端
前端示例代码loginGithub.html
...
<p>
    <button onclick="handleLoginGithub()">使用Github登录</button>
</p>
</body>
<script>
    //触发github登录
    function handleLoginGithub() {
        window.location.href = "https://github.com/login/oauth/authorize" +
            "?client_id=1994fe209a6970a75a26" +
            "&redirect_uri=http://localhost:8080" +
            "&scope=" +
            "&state=" +
            "&allow_signup=" +
            "&login="
    }
</script>
...

只有一个按钮,点击按钮,重定向到github请求code接口。参数有:

  1. client_id:注册OAuth2 App成功后的OAuth2客户端Id
  2. redirect_uri:重定向地址,与注册OAuth2 App的重定向地址保持一致。
  3. scope是申请访问的权限范围,传空,默认。
  4. state、allow_signup、login我们都默认传空值
    参数具体意义请参考官网:https://developer.github.com/apps/building-oauth-apps
后端示例代码server.js
...const server = http.createServer(function (req, res) {
    res.writeHeader(200, {
        'content-type': 'text/html;charset="utf-8"'
    });

    if (req.url === "/loginGithub.html") {
        //返回页面
        fs.readFile("./loginGIthub.html", function (err, data) {
            res.write(data);
            res.end();
        })
    } else {
        //获取回调地址中的code
        const arg = url.parse(req.url, true).query;
        //回调地址接收code
        if (arg && arg.code) {
            //如果参数中有code,说明是GitHub通过重定向传递code,携带code请求token
            const tokenUrl = "https://github.com/login/oauth/access_token" +
                "?client_id=1994fe209a6970a75a26" +
                "&client_secret=1c0de0b18501cfa419a250ebe855207ba6d2b6d7" +
                "&redirect_uri=http://localhost:8080" +
                "&state=" + arg.state +
                "&code=" + arg.code;

            //1 后台请求github的token
            request.post({url: tokenUrl}, function optionalCallback(err, httpResponse, body) {
                if (err) {
                    res.write('<h1>获取token失败</h1><p>' + err + '</p>');
                    res.end();
                } else {
                    //获取token成功
                    let token = url.parse('?' + body, true).query.access_token;
                    //2 使用token访问用户在github的信息
                    request({url: 'https://api.github.com/user', headers: {
                            'Authorization': 'token ' + token, //携带token
                            'User-Agent': 'example' //github要求必须设置User-Agent
                        }}, function (error, response, b) {
                        if (error) {
                            res.write('<h1>获取token成功,但是使用token获取用户信息失败</h1><p>' + body + '</p>');
                            res.end();
                        } else {
                            res.write('<h1>获取token成功,使用token获取用户信息成功</h1><p>' + body + '</p><p>' + b + '</p>');
                            res.end();
                        }
                    })
                }
            });
        } else {
            res.write('<h1>404</h1><p>此示例只有 http://localhost:8080/loginGithub.html 一个页面</p>');
            res.end();
        }
    }
}).listen(8080); //端口号
...

这是nodejs实现的简单后端代码,最重要的逻辑是当请求中携带形如code=xxxx&state=参数的时候,后端接受到参数中的code,然后使用reqest发起post请求获取token。当获取token成功后,再携带token获取用户信息。

运行与演示

  1. 安装nodejs环境
  2. 安装依赖的request工具包:npm install --save request
  3. 运行:node server.js
  4. 打开浏览器访问:http://localhost:8080/loginGithub.html
  5. 点击按钮:使用Github登录
    图:fangwen.png

图:shouquan.png

图:chenggong.png

总结

OAuth2客户端逻辑并不复杂,还有其他功能如刷新token等不一一赘述。然后真要实现功能的同时还保证安全性良好是有一定的难度的,因此实际项目一般不会使用这么原始的方式去自己实现OAuth2登录逻辑,而是使用各种第三方工具库。各种编程语言栈都有很多OAuth2类库,都可以便捷地实现GitHub登录,比如在java领域常用的Spring Security框架。

更多干货文章请参考:
《Spring Security实战》

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值