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

Angular16下基于Ngrx Effects实现登出撤销Token功能求助

Angular 16 结合 Google Identity 实现登出功能(NgRx版)

我正在用Angular 16搭配Google Identity与Google One Tap实现用户登录功能,当前开发登出模块,需要调用.NET后端接口撤销用户Token,计划通过分发Action触发登出流程,已完成以下实现:

已完成的实现部分

1. AuthApiService 中的 revokeToken 方法

接收email参数调用后端删除接口:

revokeToken(email: string) {
    const header = new HttpHeaders().set('Content-type', 'application/json');
    return this.httpClient.delete(`api/v1/Auth/RevokeToken/` + email, { headers: header, withCredentials: true });
}

2. 定义 AuthActions 动作组

import { createActionGroup, emptyProps, props } from '@ngrx/store';
import { HttpErrorResponse } from '@angular/common/http';

export const AuthActions = createActionGroup({
  source: 'Auth',
  events: {
    'Logout Init': emptyProps(),
    'Logout Success': emptyProps(),
    'Logout Failed': props<{ error: HttpErrorResponse }>(),
  },
});

3. AuthState 及对应 Reducer 实现

import { createFeature, createReducer, on } from '@ngrx/store';
import { AuthActions } from './auth.actions';
import { LoadingState } from '../../shared/models/loading-state.model';

export interface AuthState {
  token: string;
  email: string;
  fullName: string;
}

export const initialState: AuthState = {
  token: '',
  email: '',
  fullName: '',
};

export const authFeature = createFeature({
  name: 'auth',
  reducer: createReducer(
    initialState,

    on(AuthActions.logoutInit, (state) => ({
      ...state,
      ...LoadingState.loading(),
    })),
    on(AuthActions.logoutSuccess, (state) => ({
      ...state,
      token: '',
      email: '',
      fullName: '',
      ...LoadingState.loaded(),
    })),
    on(AuthActions.logoutFailed, (state, { error }) => ({
      ...state,
      ...LoadingState.failed(error),
    })),
  )
})

遇到的问题:NgRx Effects 无法正常工作

我编写的Effects代码无法实现预期逻辑,尝试代码如下:

revokeTokenAtLogout$ = createEffect(() => {
  return this.actions$.pipe(
    ofType(AuthActions.logoutInit),
    concatLatestFrom(() => this.store.select(selectEmail)),
    map(([action, email]) => {
      this.authApiService.revokeToken(email).pipe(
        AuthActions.logoutSuccess(),
        catchError(error => of(AuthActions.logoutFailed({error})))
      )
    })
   )
})

预期实现逻辑

  • 监听 logoutInit 动作;
  • 从Store中获取当前用户的email;
  • 将email传入revokeToken方法调用后端接口;
  • 调用成功则触发logoutSuccess并跳转至登录页;
  • 调用失败则触发logoutFailed动作。

正确解决方案

经过调试,最终实现的正确Effects代码如下:

@Injectable()
export class AuthEffects {
  constructor(
    private readonly actions$: Actions,
    private readonly store: Store,
    private readonly authApiService: AuthApiService,
    private router: Router,
  ) {}

  revokeTokenAtLogout$ = createEffect(() => {
    return this.actions$.pipe(
      ofType(AuthActions.logoutInit),
      concatLatestFrom(() => this.store.select(selectEmail)),
      switchMap(([, email]) =>
        this.authApiService.revokeToken(email).pipe(
          map(() => AuthActions.logoutSuccess()),
          catchError(error => of(AuthActions.logoutFailed({ error })))
        ),
      ),
    );
  });

  logoutNavigate$ = createEffect(() => {
    return this.actions$.pipe(
      ofType(AuthActions.logoutSuccess),
      tap(() => {
        this.router.navigate(['login']).then(() => window.location.reload());
      })
    );
  }, { dispatch: false })
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 23:27:42