实际开发中,关于单点登录之前后端分离
单点登录,简单来说,就是多个相关系统使用同一个登录页,一次登录,多系统获取Token
步骤一、重新编辑登录页面html文件,并发给后端
登录页面样式一样,只是vue文件,变为html文件,并交给后端人员部署到后台上,可以去掉之前带有表单的vue页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>登录</title>
<style>
*{
margin:0;
padding:0;
box-sizing:border-box;
}
body {
background: url(img/bg.png) no-repeat center 0px fixed;
background-size: cover;
font-family: "微软雅黑", sans-serif;
}
.login {
position: absolute;
top: 50%;
left: 50%;
margin: -150px 0 0 -150px;
width:300px;
height:300px;
}
.login h1 {
color:#555555;
text-shadow: 0px 10px 10px #CDC673;
letter-spacing:2px;text-align:center;
margin-bottom:20px;
}
input{
padding:10px;
width:100%;
color:white;
margin-bottom:10px;
background-color:#555555;
border: 1px solid black;
border-radius:5px;
letter-spacing:2px;
}
form button{
width:100%;
padding:10px;
margin-bottom:10px;
background-color:#CDC673;
border:1px solid black;
border-radius:5px;
cursor:pointer;
}
</style>
</head>
<body>
<div class="login">
<h1>单点登录系统</h1>
<!-- 这块必须是表单元素,配置属性不要变 -->
<form action="/login" method="post">
<input type="text" name="username" placeholder="用户名" required="required">
<input type="password" name="password" placeholder="密 码" required="required">
<button type="submit">登录</button>
</form>
</div>
</body>
</html>
步骤二、使用前置导航守卫
使用前置导航守卫,每一次跳转页面,都要判断token
import { toSso } from '@/api/user';
import store from '@/store';
import { getCookie } from '@/tool/cookie';
import { get } from "@/api/api";
import { getToken } from "@/api/api.js";
// 获取地址栏的code【使用后端给的code值,调用getToken接口】
function getQueryVariable(variable) {
const query = window.location.search.substring(1); // 从问号 (?) 开始的 URL(查询部分)
const vars = query.split('&');
for (let i = 0; i < vars.length; i++) {
const pair = vars[i].split('=');
if (pair[0] === variable) {
return pair[1];
}
}
return '';
};
// 前置导航守卫
router.beforeEach(async (to, from, next) => {
// cookie的设置,是后端设置的,前端只需要获取,或者置空
const accessToken = getCookie('access_token');
if (accessToken) {
const userInfo = store.state.user.userDesc.id;
if (userInfo) {
next();
} else {
// 系统第一次:调用获取用户信息的接口
const res = await get('/sso/user/get');
// 保存用户信息到Vuex
store.commit("user/setUser", res.data);
next();
}
} else {
// 调用toSso之前是没有code的
const code = getQueryVariable('code');
if (code) {
// token调用成功 才能调用用户信息接口
let dataRes = await getToken(code);
// 记录地址信息
window.location = sessionStorage.getItem('visitUri');
} else {
// 如果没有accessToken,跳转到单点系统的登录页 获取code
toSso();
}
// const whiteList = ['/home'];
// 如下是当 摇摆页是:没有表单的登录页
//if (whiteList.indexOf(to.path) !== -1) {
//next();
//} else {
//toSso();
//}
}
});
步骤三、toSso方法
// 地址都是和后端保存一致的
import _config from './http.config';
const ssoUri = _config.ssoUri;
const userInfoUri = _config.userInfoUri;
const tokenUri = _config.tokenUri;
const clientId = _config.clientId;
const callbackUri = _config.callbackUri;
// http://192.168.102.59:8080/#/index 注意:前端的#要转义成:%23
// callbackUri: 'http://192.168.102.59:8080/%23/index',
function getAuthorizeUri(state) {
// 为sso函数提供地址:
return (
ssoUri +
'authorize?client_id=' +
clientId +
'&scope=all&response_type=code&redirect_uri=' +
callbackUri // 单点登录摇摆页/重定向页面(没有表单的登录页 或者 系统首页)
);
}
export function toSso() {
sessionStorage.setItem('visitUri', window.location.href); // 页面临时缓存数据
window.location.href = getAuthorizeUri();
}
步骤四:获取cookie的方式
/**
* 设置cookie
* @param name 字段名
* @param value 值
* @param seconds 失效时长
*/
export function setCookie(name, value, seconds) {
seconds = seconds || 0; // seconds有值就直接赋值,没有为0
let expires = '';
if (seconds !== 0) {
// 设置cookie生存时间
const date = new Date();
date.setTime(date.getTime() + seconds * 1000);
expires = '; expires=' + date['toGMTString']();
}
document.cookie = name + '=' + escape(value) + expires + '; path=/';
}
/**
* 获取cookie
* @param name 字段名
*/
export function getCookie(name) {
if (document.cookie.length > 0) {
let start = document.cookie.indexOf(name + '=');
if (start !== -1) {
start = start + name.length + 1;
let end = document.cookie.indexOf(';', start);
if (end === -1) end = document.cookie.length;
return unescape(document.cookie.substring(start, end)).replace(/'/g, '');
}
}
return null;
}
步骤五、请求拦截封装
import axios from "axios";
import store from '@/store';
import { getCookie } from '@/tool/cookie';
const $http = axios.create({
baseURL: './',
timeout: 5000,
retry: 1,
retryDelay: 1000,
withCredentials: true,
})
$http.interceptors.request.use(
(config) => {
if (config.url === '/system/login/captcha') return config;
if (config.url === '/auth/oauth/token') {
const str = 'lin:123123';
const str64 = Buffer.from(str).toString('base64');
config.headers.Authorization = 'Basic ' + str64;
return config;
}
const accessToken = getCookie('access_token');
if (accessToken) {
if (!config.url.includes('http://')) {
// 让每个请求携带自定义token 请根据实际情况自行修改
config.headers['Authorization'] = 'Bearer ' + accessToken;
config.headers['Access-Control-Allow-Origin'] = '*';
config.headers['userId'] = store.state.user.userDesc.id
return Promise.resolve(config);
}
}
return config;
},
(error) => {
Promise.reject(error);
}
);
export default $http;
关于集成单点后,退出登录方式改变
// window.customizeConfig.callbackUri 摇摆页(没有表单的登录页 或者 首页)
signOut: `/logout?redirect_uri=${window.customizeConfig.callbackUri}`,
outLogin() {
// 清除用户信息
this.setUser({});
// 清除cookie
setCookie('access_token','',-1);
// window.customizeConfig.ssoAddr : 后端给的地址
window.location.href = window.customizeConfig.ssoAddr + this.url.signOut; // 此时会自动跳转到登录页
},
版权声明:本文为weixin_44224921原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。