最近项目停工了,RageFrame的学习暂时告一段落,这一篇给大家分享下有关单点登录的相关知识,并提供一些demo给大家参考,希望对想了解的朋友有一些帮助。
话不多说,先上原理(借鉴地址:https://www.jianshu.com/p/613e44d4a464)
点登录SSO(Single Sign On)说得简单点就是在一个多系统共存的环境下,用户在一处登录后,就不用在其他系统中登录,也就是用户的一次登录能得到其他所有系统的信任。单点登录在大型网站里使用得非常频繁,例如像阿里巴巴这样的网站,在网站的背后是成百上千的子系统,用户一次操作或交易可能涉及到几十个子系统的协作,如果每个子系统都需要用户认证,不仅用户会疯掉,各子系统也会为这种重复认证授权的逻辑搞疯掉。实现单点登录说到底就是要解决如何产生和存储那个信任,再就是其他系统如何验证这个信任的有效性,因此要点也就以下两个:
- 存储信任
- 验证信任
如果一个系统做到了开头所讲的效果,也就算单点登录,单点登录有不同的实现方式,本文就列出我开发中所遇见过的实现方式。
方法一:以Cookie作为凭证媒介
最简单的单点登录实现方式,是使用cookie作为媒介,存放用户凭证。
用户登录父应用之后,应用返回一个加密的cookie,当用户访问子应用的时候,携带上这个cookie,授权应用解密cookie并进行校验,校验通过则登录当前用户。
Auth via cookie
不难发现以上方式把信任存储在客户端的Cookie中,这种方式很容易令人质疑:
- Cookie不安全
- 不能跨域实现免登
对于第一个问题,通过加密Cookie可以保证安全性,当然这是在源代码不泄露的前提下。如果Cookie的加密算法泄露,攻击者通过伪造Cookie则可以伪造特定用户身份,这是很危险的。
对于第二个问题,更是硬伤。
方法二:通过JSONP实现
对于跨域问题,可以使用JSONP实现。
用户在父应用中登录后,跟Session匹配的Cookie会存到客户端中,当用户需要登录子应用的时候,授权应用访问父应用提供的JSONP接口,并在请求中带上父应用域名下的Cookie,父应用接收到请求,验证用户的登录状态,返回加密的信息,子应用通过解析返回来的加密信息来验证用户,如果通过验证则登录用户。
Auth via jsonp这种方式虽然能解决跨域问题,但是安全性其实跟把信任存储到Cookie是差不多的。如果一旦加密算法泄露了,攻击者可以在本地建立一个实现了登录接口的假冒父应用,通过绑定Host来把子应用发起的请求指向本地的假冒父应用,并作出回应。
因为攻击者完全可以按照加密算法来伪造响应请求,子应用接收到这个响应之后一样可以通过验证,并且登录特定用户。
方法三:通过页面重定向的方式最后一种介绍的方式,是通过父应用和子应用来回重定向中进行通信,实现信息的安全传递。
父应用提供一个GET方式的登录接口,用户通过子应用重定向连接的方式访问这个接口,如果用户还没有登录,则返回一个的登录页面,用户输入账号密码进行登录。如果用户已经登录了,则生成加密的Token,并且重定向到子应用提供的验证Token的接口,通过解密和校验之后,子应用登录当前用户。
Auth via redirect这种方式较前面两种方式,接解决了上面两种方法暴露出来的安全性问题和跨域的问题,但是并没有前面两种方式方便。
安全与方便,本来就是一对矛盾。
方法四:使用独立登录系统一般说来,大型应用会把授权的逻辑与用户信息的相关逻辑独立成一个应用,称为用户中心。
用户中心不处理业务逻辑,只是处理用户信息的管理以及授权给第三方应用。第三方应用需要登录的时候,则把用户的登录请求转发给用户中心进行处理,用户处理完毕返回凭证,第三方应用验证凭证,通过后就登录用户。
以上,就是我了解的单点登录的给个模式及原理,下面给大家上实战代码,这里我列举两种情况,分类给大家讲解和提供我对应的demo(以下理论参考https://www.jb51.net/article/98228.htm)环境1:a.xxx.com需要跟b.xxx.com实现跨域,这种比较简单,只需要设置cookie的域名关联域就可以了 cookie.Domain = “xxx.com”,这样两个域名间的cookie就可以互相访问,实现跨域.
demo地址展示:
系统一:sso1.linheng.xyz
系统二:sso2.linheng.xyz
vue具体代码:
先打入指令安装js-cookie
npm i js-cookie -S
然后写入登录页面
<template> <div class="hello"> <h1>{{ msg }}</h1> <button @click="handleLogin">点击登录</button> <button @click="rethome">返回首页</button> </div> </template> <script> import Cookies from 'js-cookie' export default { name: 'home', data () { return { msg: '系统一登录页面' } }, methods: { handleLogin() { var token = this.randomString(); Cookies.set('app.token',token, { expires: 1000, path: '/', domain: '.**.com' })//这里换你的网站根目录 Cookies.set('app.loginname','系统一', { expires: 1000, path: '/', domain: '.**.com' })//这里换你的网站根目录 this.$router.push("/"); }, rethome(){ this.$router.push("/"); }, randomString(e) { e = e || 32; var t = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678", a = t.length, n = ""; for (var i = 0; i < e; i++) n += t.charAt(Math.floor(Math.random() * a)); return n } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> h1, h2 { font-weight: normal; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
接下来是首页:
<template> <div class="hello"> <h1>{{ msg }}</h1> <h3>用户信息为:{{token}}</h3> <h3>登录地点:{{loginname}}</h3> <button @click="logout">登出</button> </div> </template> <script> import Cookies from 'js-cookie' export default { name: 'home', data () { return { msg: '系统一主页面', token:'', loginname:'' } }, mounted(){ const token = Cookies.get('app.token'); this.token = token; const loginname = Cookies.get('app.loginname'); this.loginname = loginname; console.log(token); if(!token){ this.$router.push("/login"); } }, methods: { logout(){ Cookies.set('app.token','', { expires: 1000, path: '/', domain: '.**.com' })//这里换你的网站根目录 Cookies.set('app.loginname','', { expires: 1000, path: '/', domain: '.**.com' })//这里换你的网站根目录 this.$router.go(0) } } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> h1, h2 { font-weight: normal; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
系统二的对应页面也只是把这两个页面弄过去,改下文字方便识别而已。
写到这里,大家对于这个的思路已经比较清晰了,如果需要优化,我这边建议大家把判断和获取的方法统一弄成控件,然后在router里进行操作,这样会更好。
这里分享下我封好的控件demo,点击这里查看文章
环境2:a.aaa.com需要跟b.bbb.com实现跨域,这种不同域名的情况下,想要实现就必须换种方式了.
这个我还没有写好demo,这个给大家提供我找到的最靠谱的思路及demo
在这里我将引入第三者,s.sss.com这个站点,就是某个浏览器同时打开了这3个站点,我们访问A站点,先判断自身是否登录,如果session为空,就重定向到S站点,判断S站点上面是否有cookie,如果S站点上面也没有cookie,则由S站点重定向到A站点的登录页.这样我们就实现了第一步,S站做的的就是隐藏在幕后,子站先判断自己是否存在session,如果不存在,就重定向到主站S上面去验证.第二步,验证登录信息合法性.这里我引入token(令牌),网上有很多资料,描述token的传递,工作方式是这样,A登录成功,保存自身的session,重定向到S,S在自己站点保存一个session跟cookie,session保存token对象{tokenID,userName,startTime,endTime},cookie保存tokenID,tokenID是一个Guid,把token对象缓存在集合里面,另起一个线程,根据endTime(过期时间)来定期清理集合列表,重定向到A的时候再将tokenID传递过去,拿到tokenID后,进入验证环节,S站有提供一个接口,根据tokenID获取token对象,如果获取到对象,且没有失效,则tokenID合法,跳入index页面.情况2,A登录,直接打开B,这时候B自身没有session,会主动请求主站,主站会返回cookieID(S站存在客户端的cookie),这个时候再走验证环节,如果通过,则B根据token对象创建自身的session,再跳入index.在这里整个单点登录就已经成功了,接下来附上流程图:
前面流程图,太丑了,这里补上一张,希望有所帮助.
收集的demo源码:SSO单点登录说明:新建2个站点xxx-xxx.com(主站),yyy-yyy.com(子站),修改hosts文件,将这两个域名都指向127.0.0.1即可.
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
到此这篇关于vue实现单点登录的N种方式 的文章就介绍到这了,更多相关vue单点登录内容请搜索NICE源码以前的文章或继续浏览下面的相关文章希望大家以后多多支持NICE源码!