You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ember-simple-auth的beforeModel钩子实现差异化认证?

实现差异化路由认证逻辑

要在Ember应用中实现你描述的差异化认证需求,核心思路是利用路由的beforeModel钩子判断当前目标路由,然后触发对应的认证流程。结合你已经自定义的JWT认证器,我们可以这样一步步实现:

1. 在父路由(Application Route)中添加路由判断逻辑

因为所有路由都会继承application路由的钩子,我们在这里统一处理认证逻辑,避免重复代码:

// app/routes/application.js
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';

export default class ApplicationRoute extends Route {
  @service session;

  beforeModel(transition) {
    const targetRoute = transition.targetName;
    const isAuthenticated = this.session.isAuthenticated;

    // 已认证状态直接放行
    if (isAuthenticated) return;

    // 区分路由处理不同认证方式
    if (targetRoute === 'mobile_messages') {
      // 处理mobile_messages页面的刷新令牌认证
      return this._authenticateWithRefreshToken();
    } else {
      // 其他页面引导到登录页,让用户输入邮箱密码
      return this.transitionTo('login');
      // 如果需要自动认证(比如记住密码),可以替换为:
      // return this._authenticateWithEmailPassword(storedEmail, storedPassword);
    }
  }

  // 私有方法:刷新令牌认证逻辑
  _authenticateWithRefreshToken() {
    const refreshToken = localStorage.getItem('refresh_token');
    
    // 没有刷新令牌则跳转到登录页
    if (!refreshToken) {
      return this.transitionTo('login');
    }

    // 调用自定义认证器,传入刷新令牌
    return this.session.authenticate('authenticator:jwt', { refresh_token: refreshToken })
      .catch((error) => {
        // 刷新令牌无效,清除存储并跳转登录
        localStorage.removeItem('refresh_token');
        this.transitionTo('login');
        console.error('刷新令牌认证失败:', error);
      });
  }

  // 可选:邮箱密码自动认证逻辑(比如记住密码场景)
  _authenticateWithEmailPassword(email, password) {
    return this.session.authenticate('authenticator:jwt', { email, password })
      .catch(() => this.transitionTo('login'));
  }
}

2. 调整自定义JWT认证器的authenticate方法

你的认证器需要根据传入的凭证类型(邮箱密码/刷新令牌)调用不同的后端接口,所以修改authenticate方法如下:

// app/authenticators/jwt.js
import JWT from 'ember-simple-auth/authenticators/jwt';

export default class CustomJWTAuthenticator extends JWT {
  authenticate(credentials, headers) {
    return new Ember.RSVP.Promise((resolve, reject) => {
      // 根据凭证判断调用哪个接口
      const authUrl = credentials.refresh_token ? '/auth/mobile_token' : '/auth/login';
      
      this.makeRequest(authUrl, credentials, headers)
        .then((response) => {
          Ember.run(() => {
            try {
              const sessionData = this.handleAuthResponse(response);
              // 如果是刷新令牌认证,记得更新本地存储的刷新令牌
              if (credentials.refresh_token && response.refresh_token) {
                localStorage.setItem('refresh_token', response.refresh_token);
              }
              resolve(sessionData);
            } catch (error) {
              reject(error);
            }
          });
        })
        .catch((error) => {
          Ember.run(() => reject(error));
        });
    });
  }
}

3. 完善登录页的认证流程

在登录页,用户提交邮箱密码后,调用认证器并存储返回的刷新令牌:

// app/routes/login.js
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';

export default class LoginRoute extends Route {
  @service session;
  @tracked email;
  @tracked password;
  @tracked errorMessage;

  // 登录提交方法
  submitLogin() {
    this.session.authenticate('authenticator:jwt', { email: this.email, password: this.password })
      .then(() => {
        // 存储刷新令牌供后续mobile_messages页面使用
        const newRefreshToken = this.session.data.authenticated.refresh_token;
        if (newRefreshToken) {
          localStorage.setItem('refresh_token', newRefreshToken);
        }
        // 认证成功跳转到默认页面
        this.transitionTo('dashboard');
      })
      .catch((error) => {
        this.errorMessage = `登录失败:${error.message}`;
      });
  }
}

4. 处理会话失效场景

在application路由中监听会话失效事件,清除刷新令牌并引导用户到登录页:

// app/routes/application.js
// ... 之前的代码 ...
init() {
  super.init(...arguments);
  this.session.on('invalidated', () => {
    localStorage.removeItem('refresh_token');
    this.transitionTo('login');
  });
}

这样就完成了差异化认证的实现:除mobile_messages外的所有页面需要用户先通过邮箱密码登录,而mobile_messages页面会自动尝试用刷新令牌完成认证,失败则引导到登录页。

内容的提问来源于stack exchange,提问作者Nick Shcherba

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:53:30