Front-end implementation of single sign-on authentication system

An authentication platform developed based on SSO single sign-on. Access control between multiple independent business systems is realized. Users only need to log in once to access all business systems that have integrated the single sign-on function, and do not need to log in to each business system one by one.

Single Sign-On Overview

concept

Single Sign On (SSO) for short. It means that in multiple application systems, users only need to log in once to access all mutually trusted application systems.

An Introduction

1. Technology selection:

The OAuto2.0 authorization protocol is used to realize the single sign-on function. This system uses Authorization Code (authorization code mode) to obtain access token (access_token)

process:
insert image description here

2. Involved systems (only front-end):

system illustrate
Unified Identity Authentication Platform For business system login, identity authentication
Management background Manage the business system with integrated single sign-on, including business system registration, modification, logout and other functions
business system It needs to integrate single sign-on, which can involve multiple business systems

Unified Identity Authentication Platform

The platform includes functions: login, registration, account management

An independent identity authentication system needs to be developed, and other business systems do not provide login portals (if the business system needs to retain its own login portal, it can integrate a single sign-on mode on its own login page, so that users can choose which login method to use according to their needs).

When the business system performs single sign-on, it will uniformly jump to the login page of the identity authentication system. After successful login, jump back to the authentication page of the business system through redirection

Note: The front and back ends of this project must be deployed under the same ip.

  • The backend interceptor will jump according to whether there is user information in the cookie
  • Cookies cannot be carried across domains. If the login system and the backend are not under the same IP, cross-domain problems will occur.
  • You can also try to solve the cross-domain problem. After trying the configuration on the Internet, you can’t find a suitable method. The easiest way is to deploy the front and back ends under the same ip.

Management background

Using the open source framework maxkey , it has been redeveloped. The background management uses the code under the maxkey-web-frontend/maxkey-web-mgt-app path.

github address: https://github.com/dromara/MaxKey.git

Framework reference address: http://ng.ant.design/docs/introduce/zh

You can associate the maxkey source code with your own warehouse through git upstream, and the maxkey project has been updated to facilitate code synchronization. Because the front end only uses the code under the maxkey-web-mgt-app path, the redundant code is shielded by sparse detection

maxKey front-end maxkey-web-mgt-app project split:

  • The first type: git clone can only be used for the entire project, and cannot specify a directory
  • The second uses sparse detection:
  1. Add upstream remote: git remote add upstream https://gitee.com/dromara/MaxKey
  2. Enable sparse checkout: git config core.sparsecheckout true
  3. Configure sparse checkout file: echo "/maxkey-web-frontend/maxkey-web-mgt-app/* " >> .git/info/sparse-checkout
  4. Pull remote code: git pull upstream main
  5. Note: After the sparse checkout, you can only pull the files in the maxkey-web-mgt-app directory, but keep the directory structure of the Maxkey project (maxkey-web-frontend/maxkey-web-mgt-app)

maxkey-web-mgt-app is developed using angular syntax, simply record the project running packaging process

Maxkey-web-mgt-app project debugging and running:

  • 1. Install npm install -g @angular/cli globally
  • 2. Initialize the project cnpm install
  • 3.ng serve

API request address baseUrl modification: environment.prod.ts (production, test environment) | environment.ts (development environment)

Project packaging: ng build (be sure to confirm whether the baseUrl environment in environment.prod.ts corresponds to it before packaging)

Modify the directory prefix after packaging: baseHref in angular.json modifies the directory prefix of the dist file deployed on the server

business system

The business system needs to modify its own login and logout functions.

Code

Unified Identity Authentication Platform

1. Login page: /user/login

After the user logs in successfully, store the returned congress and online_ticket in the cookie

// 登录
Login({
     
      commit }, userInfo) {
    
    
  userInfo.authType = 'bx-mobile'
  userInfo.state = storage.get('loginState')
  userInfo.remeberMe = false
  return new Promise((resolve, reject) => {
    
    
    loginByMobile(userInfo).then(response => {
    
    
      if (response.code == 0) {
    
    
        storage.set('token', response.data.token)
        storage.set('userId', response.data.userId)
        storage.set('userInfo', response.data)
        commit('SET_TOKEN', response.data.token)
        commit('SET_USERID', response.data.userId)
        commit('SET_USERINFO', response.data)
        VueCookies.set('congress', response.data.token, {
    
     path: '/' })
        VueCookies.set('online_ticket', response.data.ticket, {
    
     domain: getSubHostName(), path: '/' })
      }
      resolve(response)
    }).catch(error => {
    
    
      reject(error)
    })
  })
}

Judgment based on whether the parameter redirect_uri is carried in the browser queryString:

  • Carry: window.open(redirect_uri, '_self'), jump to the authorization page of the unified identity authentication platform through redirection (the cookie will be verified in the interceptor, if it fails, it will not jump)
  • Do not carry: this.$router.push('/home'), jump to the home page of the platform
// 登录
submitForm() {
    
    
  this.$refs[this.current].validate(async valid => {
    
    
    if (!valid) return
    let params = {
    
     ...this[this.current] }
    // 账号登录 密码加密
    if (this.current == 'accountForm') {
    
    
      params.password = smcrypto(params.password)
    }

    this.Login(params).then(({
     
      code, data, message }) => {
    
    
      if (code != 0) {
    
    
        this.$message.error(message, 2)
        this.getCaptcha()
        return
      }
      // 缓存用户名和手机号
      if (this.current === 'accountForm' && this.rememberUsername) {
    
    
        storage.set('rememberUsername', this.accountForm.username)
      }
      if (this.current === 'codeForm' && this.rememberMobile) {
    
    
        storage.set('rememberMobile', this.codeForm.mobile)
      }

      if (this.$route.query.redirect_uri) {
    
    
        let redirect_uri = CryptoJS.enc.Base64url.parse(this.$route.query.redirect_uri).toString(CryptoJS.enc.Utf8)
        window.open(redirect_uri, '_self')
      } else {
    
    
        this.$router.push('/home')
      }
    })
  })
}

2. Platform homepage: /home

Manage authorized third-party business systems. Users can jump from the home page to the selected business system by logging in with the identity authentication system

// 跳转其他业务系统    
gotoOtherSystem(item) {
    
    
  if(item.protocol === 'Basic' || item.inducer === 'SP') {
    
    
    window.open(item.loginUrl)
  } else {
    
    
    console.log(`${
      
      this.$store.state.baseUrl}/sign/authz/${
      
      item.id}`)
    window.open(`${
      
      this.$store.state.baseUrl}/sign/authz/${
      
      item.id}`)
  }
}

3. Authorization page: /authorize

The user of the identity authentication platform requests authorization from the user, whether the user allows the third-party business system to obtain the user's personal information

There are two modes of manual authorization and automatic authorization. Manual authorization requires manual operation by the user, and automatic authorization is imperceptible to the user

// 证实批准
approvalConfirm() {
    
    
  approvalConfirm(this.$route.query.oauth_approval).then(({
     
      code, data, message }) => {
    
    
    if (code != 0) {
    
    
      this.$message.error(message, 2)
      return
    }
    console.log('get-form表单数据', data)
    this.form.clientId = data.clientId
    this.form.appName = data.appName
    this.form.iconBase64 = data.iconBase64
    this.form.oauth_version = data.oauth_version
    this.form.user_oauth_approval = 'true'
    this.form.approval_prompt = data.approval_prompt
    
    // 授权流程为自动时, 自动触发
    if (this.form.approval_prompt == 'auto') {
    
    
      this.approvalAuthorize()
    }
  })
},

// 批准授权
approvalAuthorize() {
    
    
  approvalAuthorize(this.form).then(({
     
      code, data, message }) => {
    
    
    if (code != 0) {
    
    
      this.$message.error('提交失败', 2)
      return
    }
    if(this.form.approval_prompt == 'force') {
    
    
      this.$message.success('提交成功', 2)
    }
    // 跳转
    window.location.href = data
  })
},

// 拒绝授权
onDeny() {
    
    
  window.close()
}

4. Logout page: /user/logout

When exiting, the congress and online_ticket information cached in the cookie need to be cleared

Logout({
     
      commit, state }) {
    
    
  return new Promise((resolve) => {
    
    
    commit('SET_TOKEN', undefined)
    commit('SET_USERID', undefined)
    commit('SET_USERINFO', {
    
    })
    storage.remove('token')
    storage.remove('userId')
    storage.remove('userInfo')

    let rememberUsername = storage.get('rememberUsername')
    let rememberMobile = storage.get('rememberMobile')
    // 清除所有的键
    storage.clearAll()
    storage.set('rememberUsername', rememberUsername)
    storage.set('rememberMobile', rememberMobile)
    // 清除cookie
    VueCookies.remove('congress')
    VueCookies.remove('online_ticket')
    resolve(true)
  })
}

Judgment based on whether the parameter redirect_uri is carried in the browser queryString:

  • Carry: window.open(redirect_uri, '_self') to open, the page will be redirected to the login page of the single unified identity authentication platform, and carry the parameter redirect_uri
  • Do not carry: this.$router.push('/user/login'), jump to the login page of the unified identity authentication platform
logout().then(({
     
      code, data, message }) => {
    
    
  if (code != 0) {
    
    
    this.$message.error(message || '退出登录失败', 2)
    return
  }
  this.Logout().then(response => {
    
    
    if (process.env.NODE_ENV === 'development' || !this.redirect_uri) {
    
    
      this.$router.push('/user/login')
    } else {
    
    
      window.open(this.redirect_uri, '_self')
    }
  })
})

Management background

1. Modify the project request address baseUrl. Project packaging deployment ng bulid

environment.prod.ts

export const environment = {
    
    
  production: true,
  useHash: true,
  api: {
    
    
    baseUrl: 'http://10.110.208.213:9526/maxkey-mgt-api/', // 生产环境
    // baseUrl: 'http://192.168.202.55:9526/maxkey-mgt-api/', // 测试环境
    refreshTokenEnabled: true,
    refreshTokenType: 're-request'
  }
} as Environment;

2. In the application management, register the single sign-on function for the business system. At the same time, some configuration items can also be modified

insert image description here
insert image description here
The business system requires the following resources:

Resource Name illustrate
login address The login page address of the business system. The business system can create an authorization page address for single sign-on as the login address to distinguish single sign-on from common login.
Authentication address The address used by the business system to authorize SSO can be the same as the provided login address.
Application Name The application name refers to the full name of the business system, for example: test business system.

Fill in the above information in the application configuration and modify the configuration items. The following resources are available

Resource Name illustrate
client_id Application code, i.e. client id
client_secret Application secret key, that is, client secret key

Business system integration single sign-on front-end configuration

1. Add single sign-on entry

On the login page of the business system, add an entry, click to jump to the authorization page for single sign-on

this.$router.push('/idass')

2. Authorization & SSO page: /idass

Add idass authorization page, add /idass route, and set access whitelist permission for this route

Add interception before the route jumps. If no code is carried in the route, window.open opens the authorization redirection interface and jumps to the login page of the identity authentication platform

beforeRouteEnter(to, from, next) {
    
    
   if (!to.query.code) {
    
    
      window.open(`${
      
      vuex.state.baseUrl}/api/sso/directAuthorize`, '_self')
   } else {
    
    
      next()
   }
},

Write the following logic in the created method. If the code is carried in the route, call the single sign-on interface /api/sso/ssoLogin to obtain user information and cache it;

After the interface call is successful, execute the original code logic after successful login

created() {
    
    
  this.Login({
    
    
    userInfo: {
    
     code: this.$route.query.code },
    _this: this
  })
}

// 登录
Login({
     
      commit }, DATA) {
    
    
  let callback = response => {
    
    
    ... 原本登录后逻辑
  }

  let {
    
     userInfo, _this } = DATA
  let loginType = userInfo.code ? 'idass' : userInfo.account ? 'account' : 'code'
  switch (loginType) {
    
    
    case 'idass': // 单点登录
      ssoLoginUsingGET(userInfo).then(response => {
    
    
        if (response.code === 200) storage.set('idass', true)
        callback(response)
      })
      break
    case 'code': // 账号
      userInfo.code = undefined
      userInfo.encryptedData = undefined
      userInfo.iv = undefined
      userInfo.type = 'VERIFICATION'
      loginByMobileUsingPOST(userInfo).then(response => callback(response))
      break
    case 'account': // 验证码
      loginByPwdUsingPOST(userInfo).then(response => callback(response))
      break
  }
},

3. Single sign out function integration

If it is a single sign-on, you need to call window.open( ${vuex.state.baseUrl}/api/sso/logout, '_self') to open the single sign-out redirection method when you log out

  • This method will redirect to the exit page of the unified identity authentication platform, and carry redirect_uri
  • After logging out, it will be redirected to the login page of the unified identity authentication platform with redirect_uri
  • The user logs in again on the current page, because there is a parameter redirect_uri in the querystring, so the authorization process will go through again
// 登出
Logout({
     
      commit, state }) {
    
    
  return new Promise((resolve) => {
    
    
    if (storage.get('idass')) {
    
    
      // 清除所有的键
      storage.clearAll()
      window.open(`${
      
      vuex.state.baseUrl}/api/sso/logout`, '_self')
    } else {
    
    
      // 清除所有的键
      storage.clearAll()
      router.push('/user/login')
      resolve('200')
    }
  })
}

Guess you like

Origin blog.csdn.net/weixin_45559449/article/details/129283351