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

如何在Angular中通过Interceptor实现页面刷新后自动登录?

页面刷新后Angular自动登录实现方案

我开发了一个通过Interceptor处理登录的Angular应用,用户登录后从数据库获取JWT令牌和用户数据,将JWT存入localStorage,同时把这些信息保存到session变量中。但页面刷新后会丢失session状态,请问如何通过Interceptor实现页面刷新后的自动登录?需要调整Interceptor文件代码,同时完善auth.service.ts中的autoLogin()函数。


一、完善auth.service.ts

补全登录时的localStorage存储逻辑,同时实现完整的autoLogin功能,在应用初始化时自动恢复session状态:

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';

// 定义Session类型
interface Session {
  token: string;
  user: any;
}

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  private session = new BehaviorSubject<Session>({ token: '', user: {} });
  loginError: any;
  private api_url = '你的登录接口地址'; // 替换成实际接口地址

  constructor(private _http: HttpClient) {
    // 应用启动时自动执行自动登录逻辑
    this.autoLogin();
  }

  getToken() {
    const session = this.session.getValue();
    return session?.token;
  }

  getCurrentUser() {
    const session = this.session.getValue();
    return session?.user;
  }

  // 供组件订阅session状态变化
  getSessionObservable(): Observable<Session> {
    return this.session.asObservable();
  }

  login(credentials: any) {
    this._http.post<Session>(this.api_url, credentials).subscribe(
      (session: Session) => {
        // 将token和用户数据存入localStorage
        localStorage.setItem('token', session.token);
        localStorage.setItem('user', JSON.stringify(session.user));
        // 更新session状态
        this.session.next(session);
        this.loginError = null;
      },
      (error) => {
        if (error instanceof HttpErrorResponse) {
          this.loginError = error.error;
          console.log(this.loginError);
        }
      }
    );
  }

  autoLogin() {
    const tokenFromLocalStorage = localStorage.getItem('token');
    const userFromLocalStorage = localStorage.getItem('user');
    
    // 只有同时存在token和用户数据时才恢复状态
    if (tokenFromLocalStorage && userFromLocalStorage) {
      const parsedUser = JSON.parse(userFromLocalStorage);
      // 更新BehaviorSubject,恢复session状态
      this.session.next({
        token: tokenFromLocalStorage,
        user: parsedUser
      });

      // 可选:如果后端有token验证接口,可在这里调用验证token有效性
      // 验证失败则执行登出
      // this._http.post('/api/verify-token', { token: tokenFromLocalStorage })
      //   .subscribe({
      //     next: () => {},
      //     error: () => this.logout()
      //   });
    }
  }

  logout() {
    // 清空localStorage和session状态
    localStorage.removeItem('token');
    localStorage.removeItem('user');
    this.session.next({ token: '', user: {} });
    // 可选:跳转到登录页,需要先注入Router
    // this.router.navigate(['/login']);
  }
}

二、调整auth-interceptor.service.ts

修改拦截器,排除不需要授权的接口(比如登录接口)避免循环请求,同时优化授权头添加逻辑:

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor,
  HttpErrorResponse
} from '@angular/common/http';
import { Observable, catchError } from 'rxjs';
import { AuthService } from './auth.service';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

  constructor(private _auth: AuthService) {}

  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    // 排除不需要授权的接口,比如登录、token验证接口
    const excludedPaths = ['/api/login', '/api/verify-token'];
    if (excludedPaths.some(path => req.url.includes(path))) {
      return next.handle(req);
    }

    // 生成带授权头的请求
    const authorizedReq = this.getAuthorizedRequest(req);
    
    return next.handle(authorizedReq).pipe(
      catchError((err) => {
        // 遇到401未授权时,执行登出逻辑
        if (err instanceof HttpErrorResponse && err.status === 401) {
          this._auth.logout();
        }
        throw err;
      })
    );
  }

  getAuthorizedRequest(req: HttpRequest<any>) {
    const token = this._auth.getToken();
    // 只有存在有效token时才添加Authorization头
    if (token) {
      return req.clone({
        setHeaders: {
          Authorization: `Bearer ${token}`
        }
      });
    }
    // 无token则返回原请求
    return req;
  }
}

三、注册拦截器

在app.module.ts中注册拦截器,确保它能生效:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';

import { AppComponent } from './app.component';
import { AuthInterceptor } from './auth-interceptor.service';
import { AuthService } from './auth.service';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, HttpClientModule],
  providers: [
    AuthService,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 04:27:16