Tutorial: Custom AuthenticationToken

Custom AuthenticationToken

自定义 AuthenticationToken

不同的场景下,我们对认证需要的身份和凭证信息不同,比如在单点登录(SSO)的一种广泛使用的方案 CAS 中,我们最需要的 token 应该包含 CAS 的 ST(Service Ticket),即服务票据。因此我们应该这样定义:

// path/to/CASToken.js

const AuthenticationToken = require('egg-auths/lib/AuthenticationToken')

class CASToken extends AuthenticationToken {
  constructor (options) {
    super(options)
    // ST 在登录的时候是必传的
    this.ST = options.ST
    // 用户信息在验证通过后才有
    this.userInfo = options.userInfo || null
  }
  getST () {
    return this.ST
  }
  // 后续验证通过后设置用户信息
  setUserInfo (user) {
    this.userInfo = user
  }
}

接下来我们需要实现一个能消费这种 Token 类型的 Realm

// path/to/CASRealm

const CASToken = require('path/to/CASToken')
const Realm = require('egg-auths/lib/Realm')

class CASRealm extends Realm {
  constructor (...args) {
    super(...args)
  }
  // 静态方法 supports 用来判断是否支持某种 Token 类型
  static supports (token) {
    return token instanceof CASToken
  }
  async authenticate (token) {
    // 调用cas client 的验证 ST
    let user = await this.ctx.service.cas.validateSTAndGetUser(token.getST())
    // 设置用户信息
    token.setUserInfo(user)
    // user 必须包含一个 id 属性是唯一的,用于持久化信息并根据 id 查找
    return user
  }
  async getRoles (token) {
    // return roles
  }
  async getPermissions (roleIds) {
    // return permissions
  }
}

然后在配置文件中加入这两个类:

// application/config/config.default.js

const CASToken = require('path/to/CASToken')
const CASRealm = require('path/to/CASRealm')

config.auths = {
  realms: [CASRealm],
  tokens: [CASToken],
}
 

获取 token 信息

你可以通过 await subject.getToken() 拿到 subject 对应 token 的实例。因为 token 被序列化到外部存储媒介(redis、session等),可能需要远程访问,因此这是一个 async 方法。