第一次写sso统一登录有点紧张(๑• . •๑)
站长
· 阅读数 12
好久没写文章了,这是年前写的一个需求,也是第一次接触抱着紧张的心态,生怕写错,不过最终的结果还是很理想的,分享出来留个纪念
年后回来找工作的友友们你们还好嘛~ 要加油呀~ 春天到了,有压力的话就去吹吹风,那怕生活不如意,你也要很开心
进入主题---- 先说下我们的思路和步骤,sso登录是和服务端共同配合完成
- 需要一个单独的sso页面登录平台和需要控制的后台项目(分dev|test|product三种环境地址)对应匹配环境变量
- 原登录页改为首次进入跳转到sso登录页,点击我们需要控制的项目,携带
auth_code
跳转 - 判断
auth_code
(auth_code相当于令牌)是否有存在 - 没有
auth_code
反跳转sso登录页,有auth_code
获取token
正常登录
跟着上面所说的步骤一步步进行,会详细讲解,不要嫌我啰嗦
sso+所控制的后台项目 环境配置
下面是在test环境配置文件,其他环境依次匹配,这两个地址都是一会下面所需要的
import { defineConfig } from 'umi'
export default defineConfig ({
define: {
'process.env.UMI_APP_SSO_URL' : 'https://***-sso-test.jidan.com', // sso地址
'process.env.UMI_APP_PRODUCT_URL' : 'https://***-test.jidan.com' // 后台项目地址
}
})
环境变量依赖于UMI
当指定
UMI_ENV
时,会额外加载指定值的配置文件,需在package.json
加配置
"build:dev": "cross-env UMI_ENV=dev umi build",
"build:test": "cross-env UMI_ENV=test umi build",
"build:staging": "cross-env UMI_ENV=staging umi build",
"build:product": "cross-env UMI_ENV=product umi build",
Proxy域名代理
这个很简单,配置接口代理,一会我们拿
auth_code
去请求token
'/sso': {
target: 'https://***sso-test.jidan.com',
changeOrigin: true,
pathRewrite: {
'^/sso': ''
}
}
首次加载登录页跳转sso获取auth_code令牌
在sso项目中获取令牌,例如下
data
是服务端返回给我们的auth_code
令牌redirect_url
是需要携带auth_code
跳转的登录地址redirect_url
和data
拼接跳转
跳转到目标页面,登录页面所处理的逻辑
const { location } = props
const handleLogin = () => {
const { dispatch } = props
const { auth_code } = location.query // 获取从sso地址携带过来的code令牌
if (auth_code) { // 判断是否有令牌
dispatch({ // 触发models状态管理下login里面的effects进行异步通讯
type: 'login/ssoLogin',
payload: { auth_code },
})
} else {
const { NODE_ENV } = process.env // 判断当前环境跳转回sso登录页重新验证获取令牌
let loginUrl = `${process.env.UMI_APP_SSO_URL}/login?from=${window.location.href}`
if (NODE_ENV === 'development') {
loginUrl += `&productUrl=${process.env.UMI_APP_PRODUCT_URL}`
}
window.location.href = loginUrl
}
}
useEffect(() => {
handleLogin()
}, [])
传令牌获取数据库对应token-登录成功
effects
是一个action
动作,用于和服务端进行交互,用*
定义的函数,通过yield
触发异步逻辑,得到服务端响应的数据可以用put
方法触发reducer
来修改数据
effects: {
*ssoLogin ({ payload }, { call, put }) {
// 触发ssoLogin接口获取token
const response: ResponseType = yield call(ssoLogin, payload)
// 在reducer存储得到的token
yield put({
type: 'changeSsoLoginStatus',
payload: {
type: ACCOUNT_TYPE,
status: response.result === 'success' ? 'ok' : 'error',
data: response?.token,
errMsg: response.info || '',
},
})
// ssoLogin接口响应成功
if(response.result === 'success'){
// 用得到的token获取用户信息
if (response?.token) {
const responseUser: ResponseType = yield call(getUserInfos, response.token)
// 存储用户信息
yield put({
type: 'user/saveCurrentUser',
payload: {
name: responseUser.data.name,
userid: responseUser.data.id,
token: responseUser.data.token,
},
})
// 登录成功
history.replace("/**")
} else {
notification.error({
description: '获取用户id异常',
message: '请求失败',
})
}
}else{
// 响应失败或者令牌过期返回重定向页面
Modal.confirm({
title: '登录失败',
okText: '重新登录',
cancelText: '取消',
onOk: () => {
window.location.href = '/'
},
})
}
},
}
存储token
reducer
是一个函数,同步动作,用来修改数据,会返回老的或者新的state
reducers: {
changeSsoLoginStatus (state, { payload }) {
const { data } = payload
// 存储token用于登录后的其他接口token过期操作
setToken(data || 'token')
return {
...state,
currentAuthority: CURRENT_AUTHORITY as authorityType,
status: payload.status,
type: payload.type,
errMsg: payload.errMsg,
}
},
},
以上就是一整个前端操作了,第一次写sso登录,有点紧张