前后端分离下的第三方登陆处理

第三方登陆的种类分析

  1. 前后端不分离的情况,后端根据第三方回调返回的用户信息可以直接登陆用户,这种比较简单,后端拿到用户可以直接使用session记住并且登陆用户,跳转到相应页面。
  2. 前后端分离,但是不跨域
  3. 前后端分离,并且是跨域的,即前端域名和后端api域名不同

github 为例子:

首先去添加一个 Oauth App:

github Oauth Apps

配置相关回调地址,这里的回调地址必须必须能通过外网访问。或者你可以用内网穿透。

配置

配置完后把你的 IDsecret 加入到你的后端逻辑中去,

秘钥

之后用户通过前端授权按钮登陆,首次登陆需要授权。

授权

授权完成后 github 会调用你的回调地址返回用户信息:

github回调

获取到用户信息后逻辑就开始区分了

  1. 前后端不分离的话可以直接在回调方法中登陆用户跳转
  2. 前后端分离的话比较麻烦,请继续看

分离环境下,后端会先把 github 回调的用户信息存到数据库中,然后再做相应处理。

因为 github 调用的是你后端 api 的地址,比如调用地址的域名为 api.server.com ,然而你web端的地址是 web.server.com ,这时候如何去登陆用户呢?

难题:

因为前后端分离中的后端几乎都是返回 json 格式的信息,几乎不存在直接跳前端页面的做法,并且前后端分离都是用token获取用户信息。前端只有拿到相应的token才能获取到github用户的资料。所以这里的问题变成了如何通过后端把用户的 token 给到前端页面。

解决方案:

本质上来讲这个问题属于跨域问题,只有同源的数据才能相互访问。

1995年,同源政策由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策。

最初,它的含义是指,A 网页设置的 Cookie,B 网页不能打开,除非这两个网页“同源”。所谓“同源”指的是”三个相同“。

  • 协议相同
  • 域名相同
  • 端口相同

举例来说,http://www.example.com/dir/page.html这个网址,协议是http://,域名是www.example.com,端口是80(默认端口可以省略),它的同源情况如下。

  • http://www.example.com/dir2/other.html:同源
  • http://example.com/dir/other.html:不同源(域名不同)
  • http://v2.www.example.com/dir/other.html:不同源(域名不同)
  • http://www.example.com:81/dir/other.html:不同源(端口不同)
  • https://www.example.com/dir/page.html:不同源(协议不同)

那么如何解决跨域问题的,这里我采用了,跨文档通信 API(Cross-document messaging)。window.postMessage() 。(HTML5 为了解决跨域窗口通信这个问题,引入的一个全新的API)。

下面开始实践

前端页面:

前端oauth入口

点击 github logo,跳转到后端的 api.server.com/oauth/login,为了好看,你可以采用弹出小窗的形式,类似于下面这样

小窗效果图

弹出窗口->github 授权登陆->后端接收到用户的json信息

后端:

后端得到github回调用户信息后,去生成一串 token,怎么实现的话,问你自己咯😀,生成token之后,后端必须跳转一个页面(但不是跳转到前端页面,这样不可行,直接把token放在url地址上也不安全),正确的方法是跳一个类似于下面这样的页面(注意这个行为是后端做的)。domain是你前端的域名 web.server.com

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>oauth github</title>
</head>
<body>
登陆中...
<script>
    window.onload = function () {
        window.opener.postMessage("bearer {{ $token }}", "{{ $domain }}");
        window.close();
    }
</script>
</body>
</html>

后端跳转

用户几乎是不会感觉到这个行为的,非常快!

这个页面的意义在于和前端通信,把token传给前端,

前端点击跳出小窗口的代码:

href () {
        # 弹出 500 * 500 的窗口
      window.open(this.githubUrl, 'newwindow', 'height=500, width=500, top=0, left=0, toolbar=no, menubar=no, scrollbars=no, resizable=no,location=n o, status=no')

      # 通过监听,父页面可以拿到子页面传递的token,父(前端页面),子(小窗)
      window.addEventListener('message', function (e) {
        this.me(e.data).then(() => {
          console.log('用户信息获取成功')
          this.setToken(e.data)
        }).catch(() => {
          this.setToken('')
        })
      }, false)
},

如果不知道上面代码的实现原理或者有疑问请看这里 https://wangdoc.com/javascript/bom/same-origin.html#windowpostmessage

我们假设有两个网站,1.com与2.com,我在1.com的页面上通过iframe或window.open或超链接打开了一个2.com的网页,此时我要在2.com上做操作的时候,给1.com传值,让1.com有所变化。这个过程就是个跨域的过程。

如果你对window.open熟,你就会知道通过window.open打开的网页(我们称之为子网页),可以通过window.opener对象,访问到把它打开的页面(父网页),这样一来,调用父页面的函数就是非常简单的事了。但是,在跨域的条件下,window.opener就成了一个空对象,“没有权限”,浏览器会这么告诉你。
比如,你的父页面有个函数叫callback,然后你子页面本可以这样调用:window.opener.callback(),同域时能成功,跨域时就没有权限了。
但是,此时你调用window.opener.postMessage(),却可以成功!

嗯,拿到token了之后怎么做上面代码也写了,聪明的你应该看懂了😁

这种方式的安全性

MDN 上对其这样介绍

window.postMessage() 方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为https),端口号(443为https的默认值),以及主机 (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。

演示一下

演示

你可以来 我的博客 体验一下

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,376评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,126评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,966评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,432评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,519评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,792评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,933评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,701评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,143评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,488评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,626评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,292评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,896评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,324评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,494评论 2 348

推荐阅读更多精彩内容