vue sso 单点登录
sso单点登录有很多种实现方式,我这只是采用一种最简单的实现方式 vue2 + 采用mock.js来模拟后台接口验证
- 实现的思路
sso-serve 一个独立的登录系统 http://localhost:8090/ sso_client 子级系统 ,所有子系统的逻辑大概相同
-
子系统通过截取浏览器的url 地址来判断当前系统是否登录 -
如果未登录则跳转到sso登录界面并会带上当前系统的url地址 -
sso登录界面验证账号密码,通过后会根据之前带过来的子系统url地址跳转,并带回参数st,st=后面的值在子系统在调用后台接口去验证,验证通过则会在浏览器set一个Cookies,后面打开子系统的话会根据这个Cookies来验证登录状态
- sso界面获取当前的url地址 做逻辑判断
sso 登录页代码
<template>
<div class="container login" v-if="isMounted">
<div v-if="needLogin">
<el-form :model="loginFormData">
<el-form-item label="用户名" required>
<el-input v-model="loginFormData.username"></el-input>
</el-form-item>
<el-form-item label="密码" required>
<el-input v-model="loginFormData.password"></el-input>
</el-form-item>
<el-form-item>
<el-button @click="hanldLoginInfo">登录</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import { login, loginInfo } from '@/api/sso.js'
import axios from 'axios'
export default {
name: 'App',
data() {
return {
isMounted: false,
needLogin: true,
loginFormData: {
username: '',
password: '',
},
https: '',
}
},
mounted() {
let hash = window.location.href
if (hash == '' || hash.indexOf('?') == -1) {
this.isMounted = true
} else {
let str = hash.split('?')[1]
this.https = str.split('=')[1]
this.https = decodeURIComponent(this.https)
this.getinfo()
}
},
methods: {
hanldLoginInfo() {
axios.post('/sso/login', this.loginFormData).then((infos) => {
if (infos.data.code == 0) {
let st = infos.data.data.st
if(this.https == ''){
this.https = 'http://localhost:8080/'
}
if (st !== '' && this.https !== '') {
window.location.href = `${this.https}?&st=${st}`
}
} else {
console.log(infos, 'infos异常')
}
})
},
getinfo() {
axios.post('/sso/info').then((res) => {
if (res.data.code == 0) {
console.log(res, '/sso/info验证成功')
let ist = res.data.data.st
window.location.href = `${this.https}?&st=${ist}`
} else {
console.log(res, 'infos异常')
this.isMounted = true
}
})
},
},
}
</script>
<style lang="scss" scoped>
.container {
height: 1000px;
width: 800px;
margin: auto;
background: pink;
}
.login {
font-size: 30px;
text-align: center;
line-height: 800px;
}
</style>
sso的mock.js
const bodyParser = require('body-parser')
const jsonParser = bodyParser.json()
const cookieParser = require('cookie-parser')
module.exports = function (app) {
app.use(jsonParser)
app.use(cookieParser())
app.post('/client/serviceValidate', function(req, res) {
if(req.body.st == '1234567890') {
res.cookie("S1ID",'1234567890',{maxAge: 900000, httpOnly: true});
res.send({
"code": 0,
"msg": "验证成功",
"data": {
"id": null,
"userName": "小明",
"phone": "13123553333",
"certificateCode": "2637482368437562847365",
"st": null,
"removeTag": null,
"createTime": null,
"createUser": null,
"lastModifyTime": null,
"lastOperator": null
}
})
} else {
res.send({
code: 10403,
msg: '未登录',
data: null
})
}
})
}
sso_client 子系统代码
<template>
<div id="app">
<div v-if="isLogin">ssoLOgin===未登录</div>
<div v-else>已登录===</div>
</div>
</template>
<script>
import { serviceValidate, login, logout } from './sso.js'
import { getQuery } from './url.js'
import { gotoSsoserver } from './tools.js'
import axios from 'axios'
export default {
name: 'App',
data() {
return {
isLogin: true,
content: '',
}
},
mounted() {
let str = sessionStorage.getItem('st')
console.log(str,'=====str');
if (str != '' || str != null) {
this.ssologins(str)
}
},
methods: {
async init() {
const query = getQuery(location.href)
if (query.st !== undefined) {
serviceValidate(query.st).then((data) => {
this.isLogin = true
this.content = `用户:${data.data.userName},电话:${data.data.phone}`
history.replaceState({}, '', location.origin)
})
} else {
try {
let data = await login()
this.isLogin = true
this.content = `用户:${data.data.userName},电话:${data.data.phone}`
this.$message('您已登录')
return
} catch (e) {
console.log(e)
if (e.code) {
this.$confirm('您未登录,是否跳转到SSO登录页面?', '提示')
.then(() => {
gotoSsoserver(location.href)
})
.catch(() => {})
}
}
}
},
async logout() {
try {
await logout()
this.$message('您已登出')
setTimeout(() => {
window.location.href = ''
}, 2000)
} catch (e) {
this.$message('登出接口出错')
}
},
async ssologins(val) {
let st = val
if (st == '' || null) return false
const result = await axios.post('/client/serviceValidate', {
st: st,
})
console.log(result)
if (result.data.code == '10403') {
this.isLogin = true
let hash = window.location.href
setTimeout(() => {
window.location.href = `http://localhost:8090/?st=` + encodeURIComponent(hash)
}, 2000)
} else if (result.data.code == 0) {
console.log(result, '===result登录成功')
this.isLogin = false
}
},
getURl() {
let hash = window.location.href
if (hash == '' || hash.indexOf('?') == -1) {
let redirectUrl = window.location.href
console.log(redirectUrl, '没有url')
if (redirectUrl !== '') {
window.location.href =
`http://localhost:8090/=` + encodeURIComponent(redirectUrl)
}
} else {
let str = hash.split('?')[1]
let st = str.split('=')[1]
this.ssologins(st)
}
},
},
}
</script>
<style lang="scss" scoped>
.container {
height: 1000px;
width: 800px;
margin: auto;
background: grey;
}
.login {
font-size: 30px;
text-align: center;
line-height: 800px;
}
</style>
sso_client 子系统的mock.js代码
const bodyParser = require('body-parser')
const jsonParser = bodyParser.json()
const cookieParser = require('cookie-parser')
module.exports = function (app) {
app.use(jsonParser)
app.use(cookieParser())
app.post('/client/serviceValidate', function(req, res) {
if(req.body.st == '1234567890') {
res.cookie("S1ID",'1234567890',{maxAge: 900000, httpOnly: true});
res.send({
"code": 0,
"msg": "验证成功",
"data": {
"id": null,
"userName": "小明",
"phone": "13123553333",
"certificateCode": "2637482368437562847365",
"st": null,
"removeTag": null,
"createTime": null,
"createUser": null,
"lastModifyTime": null,
"lastOperator": null
}
})
} else {
res.send({
code: 10403,
msg: '未登录',
data: null
})
}
})
}
```javascript
在 sso_client 的mian.js 或者登录页引入 stoken.js 代码进行逻辑判断
import {
Message
} from 'element-ui'
let hash = window.location.href
console.log(hash,'hash')
let st = ''
class ssotoken {
constructor() {
this.GetUrl()
this.initsso()
}
initsso() {
if (hash == '' || hash.indexOf('&st') == -1) {
let redirectUrl = window.location.href
if (redirectUrl !== '') {
Message.warning('账号未登录,正在跳转到sso登录页')
setTimeout(() => {
window.location.href = `http://localhost:8090/?st=` + encodeURIComponent(redirectUrl)
}, 2000);
}
} else {
console.log(this.GetUrl())
st = this.GetUrl().st
sessionStorage.setItem('st', st)
}
}
GetUrl() {
let url = window.location.search
let urlst = new Object()
if (url.indexOf('?') != -1) {
let str = url.substr(1)
if (str.indexOf('&st') != -1) {
let st = str.split('&st')
for (let index = 0; index < st.length; index++) {
urlst = {st:unescape(st[index].split("=")[1])}
}
}
}
return urlst
}
}
module.exports = new ssotoken
|