Как сохранить аутентификацию в pwa через перезапуски pwa? - PullRequest
0 голосов
/ 14 апреля 2019

У меня есть приложение, которое использует стратегию спа из auth0 для аутентификации пользователей. Аутентификация сохраняется, пока у меня есть подключение к интернету, потому что я могу проверить, есть ли у пользователя isAuthenticated(), когда он получает доступ к странице, требующей аутентификации. Если он не аутентифицирован, я пытаюсь обновить токен, который работает до тех пор, пока не истек срок действия его предыдущего токена, и я могу перенаправить его на нужную страницу. Если невозможно обновить токен, я прошу пользователя снова войти в систему. Так что это прекрасно работает, когда пользователь онлайн. Но так как я хотел бы также заставить его работать как pwa, обычно это означает, что я хотел бы, чтобы пользователь также мог использовать приложение, когда он находится в автономном режиме, я изо всех сил пытаюсь найти стратегию, чтобы сделать это возможным.

Есть ли у вас какие-либо предложения о том, какую стратегию использовать, если я хотел бы добавить эту автономную функциональность? Я думаю, что одним из способов было бы добавить дату истечения срока действия и затем idtoken в локальное хранилище, и просто решить, вошел ли пользователь в систему, основываясь на том, есть ли у него idtoken и истек ли его токен, но насколько я знаю, это плохая практика, поэтому я бы предпочел избежать этого.

Я использую vue и vue-router и проверяю перед каждым доступом к аутентифицированному маршруту, аутентифицирован ли пользователь следующим образом:

router.beforeEach((to, from, next) => {
  if (to.meta.requiresAuth && !auth.isAuthenticated()) {
    auth.renewTokens()
      .then(() => {
        if (!auth.isAuthenticated()) {
          next({ name: 'Index' })
        } else {
          next()
        }
      })
      .catch(() => next({ name: 'Index' }))
  } else {
    next()
  }
})

Вот мой текущий код authService.js:

import auth0 from 'auth0-js'
import EventEmitter from 'events'
import authConfig from './authConfig.json'

const webAuth = new auth0.WebAuth({
  domain: authConfig.domain,
  redirectUri: `${window.location.origin}/callback`,
  clientID: authConfig.clientId,
  responseType: 'id_token',
  scope: 'openid profile email'
})

const localStorageKey = 'loggedIn'
const loginEvent = 'loginEvent'

class AuthService extends EventEmitter {
  idToken = null;
  profile = null;
  tokenExpiry = null;

  // Starts the user login flow
  login (customState) {
    webAuth.authorize({
      appState: customState
    })
  }

  // Handles the callback request from Auth0
  handleAuthentication () {
    return new Promise((resolve, reject) => {
      webAuth.parseHash((err, authResult) => {
        if (err) {
          reject(err)
        } else {
          this.localLogin(authResult)
          resolve(authResult.idToken)
        }
      })
    })
  }

  localLogin (authResult) {
    this.idToken = authResult.idToken
    this.profile = authResult.idTokenPayload

    // Convert the JWT expiry time from seconds to milliseconds
    this.tokenExpiry = new Date(this.profile.exp * 1000)

    localStorage.setItem(localStorageKey, 'true')

    this.emit(loginEvent, {
      loggedIn: true,
      profile: authResult.idTokenPayload,
      state: authResult.appState || {}
    })
  }

  renewTokens () {
    return new Promise((resolve, reject) => {
      if (localStorage.getItem(localStorageKey) !== 'true') {
        return reject(new Error('Not logged in'))
      }

      webAuth.checkSession({}, (err, authResult) => {
        if (err) {
          reject(err)
        } else {
          this.localLogin(authResult)
          resolve(authResult)
        }
      })
    })
  }

  logout () {
    localStorage.removeItem(localStorageKey)

    this.idToken = null
    this.tokenExpiry = null
    this.profile = null

    webAuth.logout({
      returnTo: window.location.origin
    })

    this.emit(loginEvent, { loggedIn: false })
  }

  isAuthenticated () {
    return (
      Date.now() < this.tokenExpiry &&
      localStorage.getItem(localStorageKey) === 'true'
    )
  }
}

export default new AuthService()

...