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

Angular登录后获取用户数据并映射至user接口问题求助

解决方案:从JWT解析用户信息并全局展示

核心思路

  1. 从JWT Token中解析出用户字段,映射到规范的User接口
  2. 用BehaviorSubject维护全局用户状态,让任意组件可订阅获取
  3. 登录/登出时同步更新用户状态,页面刷新时自动恢复用户信息

步骤1:修正接口命名(符合TypeScript规范)

把小写的user接口改为大写User,统一命名风格:

export interface User {
  userId: string;
  userName: string;
  firstName: string;
  lastName: string;
  role: string[];
}

步骤2:升级AuthenticationService

添加用户状态管理和Token解析逻辑,支持全局用户状态共享:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { EnvironmentUrlService } from './environment-url.service';
import { UserRegistrationDto } from '../models/user/UserRegistrationDto.model';
import { RegistrationResponseDto } from '../models/user/response/RegistrationResponseDto.model';
import { UserAuthenticationDto } from '../models/user/UserAuthenticationDto.model';
import { AuthResponseDto, User } from '../models/user/response/AuthResponseDto.model';
import { Subject, BehaviorSubject, Observable, map } from 'rxjs';
import { JwtHelperService } from '@auth0/angular-jwt';

@Injectable({
  providedIn: 'root'
})
export class AuthenticationService {
  private authChangeSub = new Subject<boolean>();
  public authChanged = this.authChangeSub.asObservable();
  
  // 用BehaviorSubject存储当前用户,初始值为null,支持组件订阅
  private currentUser$ = new BehaviorSubject<User | null>(null);
  public currentUser = this.currentUser$.asObservable();

  constructor(
    private http: HttpClient, 
    private envUrl: EnvironmentUrlService, 
    private jwtHelper: JwtHelperService
  ) {
    // 页面初始化时自动检查本地token,恢复用户状态
    this.initCurrentUser();
  }

  public registerUser = (route: string, body: UserRegistrationDto) => {
    return this.http.post<RegistrationResponseDto>(this.createCompleteRoute(route, this.envUrl.urlAddress), body);
  }

  public loginUser = (route: string, body: UserAuthenticationDto) => {
    return this.http.post<AuthResponseDto>(this.createCompleteRoute(route, this.envUrl.urlAddress), body);
  }

  public sendAuthStateChangeNotification = (isAuthenticated: boolean) => {
    this.authChangeSub.next(isAuthenticated);
  }

  public logout = () => {
    sessionStorage.removeItem("token");
    this.currentUser$.next(null); // 登出时清空用户信息
    this.sendAuthStateChangeNotification(false);
  }

  public isUserAuthenticated = (): boolean => {
    const token = sessionStorage.getItem("token");
    return token && !this.jwtHelper.isTokenExpired(token);
  }

  // 解析Token并映射到User接口,注意字段要和JWT Payload完全匹配
  private parseTokenToUser(token: string): User {
    const decodedToken = this.jwtHelper.decodeToken(token);
    return {
      userId: decodedToken.userId || decodedToken.sub,
      userName: decodedToken.userName || decodedToken.username,
      firstName: decodedToken.firstName,
      lastName: decodedToken.lastName,
      role: decodedToken.role || decodedToken.roles
    };
  }

  // 初始化当前用户(页面刷新时恢复状态)
  private initCurrentUser(): void {
    const token = sessionStorage.getItem("token");
    if (token && !this.jwtHelper.isTokenExpired(token)) {
      const user = this.parseTokenToUser(token);
      this.currentUser$.next(user);
    }
  }

  // 登录成功后更新用户信息
  public setCurrentUser(token: string): void {
    const user = this.parseTokenToUser(token);
    this.currentUser$.next(user);
  }

  private createCompleteRoute = (route: string, envAddress: string) => {
    return `${envAddress}/${route}`;
  }
}

步骤3:修改LoginComponent,登录成功后同步用户状态

loginUser = (loginFormValue: any) => {
  this.showError = false;
  const formValues = {... loginFormValue };

  const userForAuth: UserAuthenticationDto = {
    email: formValues.email,
    password: formValues.password
  }

  this.authService.loginUser('api/accounts/login', userForAuth)
  .subscribe({
    next: (res:AuthResponseDto) => {
      sessionStorage.setItem("token", res.token);
      this.authService.setCurrentUser(res.token); // 新增:解析Token并设置全局用户
      this.authService.sendAuthStateChangeNotification(res.isAuthSuccessful);
      this.notificationService.showNotification('success','Login successfully');
      this.router.navigate([this.returnUrl]);
    },
    error: (err: HttpErrorResponse) => {
      this.errorMessage = err.message;
      this.showError = true;
    }
  })
}

步骤4:在任意组件(比如首页)展示用户信息

以HomeComponent为例:

import { Component, OnInit } from '@angular/core';
import { AuthenticationService } from '../services/authentication.service';
import { User } from '../models/user/response/AuthResponseDto.model';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
  currentUser: User | null = null;

  constructor(private authService: AuthenticationService) {}

  ngOnInit(): void {
    // 订阅用户状态变化,实时获取最新用户信息
    this.authService.currentUser.subscribe(user => {
      this.currentUser = user;
    });
  }
}

对应的HTML模板:

<div *ngIf="currentUser">
  <h3>欢迎回来,{{ currentUser.firstName }} {{ currentUser.lastName }}!</h3>
  <p>用户名:{{ currentUser.userName }}</p>
</div>

关键注意点

  • JWT字段匹配:parseTokenToUser方法中的字段必须和后端生成的JWT Payload字段完全一致,比如后端返回的是user_id,则需要改为decodedToken.user_id
  • 页面刷新恢复:通过initCurrentUser方法,页面刷新时自动从sessionStorage读取Token并解析用户信息,避免状态丢失
  • 状态实时同步:所有需要展示用户信息的组件,只需订阅authService.currentUser即可实时获取最新状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 23:20:39