likes
comments
collection
share

第一次写sso统一登录有点紧张(๑• . •๑)

作者站长头像
站长
· 阅读数 12

好久没写文章了,这是年前写的一个需求,也是第一次接触抱着紧张的心态,生怕写错,不过最终的结果还是很理想的,分享出来留个纪念

年后回来找工作的友友们你们还好嘛~ 要加油呀~ 春天到了,有压力的话就去吹吹风,那怕生活不如意,你也要很开心

进入主题---- 先说下我们的思路和步骤,sso登录是和服务端共同配合完成

  1. 需要一个单独的sso页面登录平台和需要控制的后台项目(分dev|test|product三种环境地址)对应匹配环境变量
  2. 原登录页改为首次进入跳转到sso登录页,点击我们需要控制的项目,携带auth_code跳转
  3. 判断auth_code(auth_code相当于令牌)是否有存在
  4. 没有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_urldata拼接跳转

第一次写sso统一登录有点紧张(๑• . •๑)

跳转到目标页面,登录页面所处理的逻辑

  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登录,有点紧张