基于ESA隐式授权认证,如何为已认证用户加载应用模板店铺模型数据
实现认证后加载店铺数据到导航栏的方案
既然你已经搞定了隐式授权,并且导航栏的认证判断逻辑也写好了,接下来只需要把店铺数据的加载和模板渲染串联起来就行,下面是具体的实现步骤:
1. 在Application路由中处理数据加载
因为导航栏属于Application模板,对应的application.js路由是加载全局数据的最佳位置——它是所有路由的父路由,会在应用启动时执行,而且能方便地结合会话状态控制数据加载。
修改你的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; // 注入会话服务 @service store; // 注入数据仓库服务 async model() { // 仅当用户已认证时,加载所有店铺数据 if (this.session.isAuthenticated) { return this.store.findAll('shop'); // 这里的`shop`是你的数据模型名称,按需修改 } // 未认证时返回空数组,避免模板报错 return []; } }
2. 在Application模板中渲染店铺列表
在你已经写好的{{#if session.isAuthenticated}}代码块里,遍历路由返回的模型数据即可:
{{!-- app/templates/application.hbs --}} {{#if session.isAuthenticated}} <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false"> 我的店铺 </a> <ul class="dropdown-menu"> {{!-- 遍历路由传递的模型数据 --}} {{#each @model as |shop|}} <li><a class="dropdown-item" href={{route 'shops.show' shop}}>{{shop.name}}</a></li> {{else}} <li><span class="dropdown-item-text">暂无可用店铺</span></li> {{/each}} </ul> </li> {{/if}}
3. 处理认证状态动态变化的场景
上面的代码能解决应用启动时已认证用户的店铺加载,但如果用户是在应用运行过程中登录的(比如从登录页跳转回来),session的isAuthenticated状态变化后,需要重新触发数据加载。可以在路由里监听会话的认证成功事件:
更新app/routes/application.js:
import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; import { scheduleOnce } from '@ember/runloop'; export default class ApplicationRoute extends Route { @service session; @service store; init() { super.init(...arguments); // 监听登录成功事件,刷新路由重新加载数据 this.session.on('authenticationSucceeded', () => { scheduleOnce('afterRender', this, () => { this.refresh(); // 调用refresh会重新执行model钩子 }); }); } async model() { if (this.session.isAuthenticated) { return this.store.findAll('shop'); } return []; } willDestroy() { super.willDestroy(...arguments); // 移除事件监听,避免内存泄漏 this.session.off('authenticationSucceeded'); } }
可选:用Controller管理数据(更灵活的方式)
如果需要更精细地控制数据的加载状态(比如显示加载中提示),或者后续要做数据更新,可以把数据逻辑放到Application控制器里:
控制器代码
// app/controllers/application.js import Controller from '@ember/controller'; import { inject as service } from '@ember/service'; import { tracked } from '@glimmer/tracking'; import { task } from 'ember-concurrency'; export default class ApplicationController extends Controller { @service session; @service store; @tracked shops = []; // 用tracked标记,自动响应数据变化 constructor() { super(...arguments); // 监听登录/登出事件,更新数据 this.session.on('authenticationSucceeded', () => this.loadShops.perform()); this.session.on('invalidationSucceeded', () => this.shops = []); } // 用ember-concurrency的task处理异步加载,自带加载状态 @task *loadShops() { if (this.session.isAuthenticated) { this.shops = yield this.store.findAll('shop'); } } init() { super.init(...arguments); // 应用启动时如果已认证,直接加载数据 if (this.session.isAuthenticated) { this.loadShops.perform(); } } willDestroy() { super.willDestroy(...arguments); // 清理事件监听 this.session.off('authenticationSucceeded'); this.session.off('invalidationSucceeded'); } }
对应模板修改
{{!-- app/templates/application.hbs --}} {{#if session.isAuthenticated}} <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false"> 我的店铺 </a> <ul class="dropdown-menu"> {{#if this.loadShops.isRunning}} <li><span class="dropdown-item-text">加载中...</span></li> {{else}} {{#each this.shops as |shop|}} <li><a class="dropdown-item" href={{route 'shops.show' shop}}>{{shop.name}}</a></li> {{else}} <li><span class="dropdown-item-text">暂无可用店铺</span></li> {{/each}} {{/if}} </ul> </li> {{/if}}
内容的提问来源于stack exchange,提问作者belgoros
相关产品推荐
相关产品推荐

