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

Angular应用中AuthGuard无法识别sessionId会话Cookie问题

Angular 15.2.0中AuthGuard无法识别HttpOnly会话Cookie的问题

问题概述

在Angular 15.2.0应用中,AuthGuard无法正确识别名为sessionId的会话Cookie。已实现用户身份验证功能,预期存在sessionId Cookie时自动跳转至主页面,但尽管浏览器开发者工具中确认Cookie存在,CookieService的getCookie函数始终返回null,导致已登录用户被拦截至登录页面。

环境信息

  • Angular版本:15.2.0
  • 后端Golang版本:1.20

代码片段

app-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { MainPageComponent } from './main-page/main-page.component';
import {AuthGuard} from './shared/auth.guard';
import { ChatComponent } from './shared/chat/chat.component';
import { SidebarLayoutComponent } from './shared/sidebar-layout/sidebar-layout.component';
import { SigninPageComponent } from './signin-page/signin-page.component';
import { SignupPageComponent } from './signup-page/signup-page.component';

const routes: Routes = [
  { path: 'signup', component: SignupPageComponent },
  { path: 'signin', component: SigninPageComponent },
  {
    path: '',
    component: MainPageComponent,
    canActivate: [AuthGuard],
    children: [
      { path: '', component: SidebarLayoutComponent, outlet: 'sidebar' },
      { path: '', component: ChatComponent, outlet: 'chat' }
    ]
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

auth.guard.ts

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(
  private auth: AuthService,
  private router: Router
) {}

canActivate(
  route: ActivatedRouteSnapshot,
  state: RouterStateSnapshot
): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
  if (this.auth.isAuthenticated()) {
    return true; // This allows access to the protected route.
  } else {
    console.error('User is not authenticated');
    return this.router.createUrlTree(['/signin']);
  }
}
}

auth.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { CookieService } from './cookie.service';

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  constructor(
    private http: HttpClient,
    private cookieService: CookieService
  ) {}

  authRequest(url: string, User: object ) {
    return this.http.post(url, User, {observe: 'response', withCredentials: true });
  };

  isAuthenticated(): boolean {
    const token = this.cookieService.getCookie('sessionId');
    console.log('Token:', token);
    return !!token;
  }

}

cookie.service.ts

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class CookieService {
getCookie(name: string): string | null {
  const allCookies = document.cookie;
  console.log('All Cookies:', allCookies);

  const cookieValue = allCookies
    .split('; ')
    .find(row => row.trim().startsWith(name + '='));

  if (cookieValue) {
    return cookieValue.split('=')[1];
  }

  return null;
}
}

Golang设置Cookie代码

session := sessions.Default(c)
session.Options(sessions.Options{
  Path:     "/", // Set the desired path
  Domain:   "localhost", // Set the desired domain
  MaxAge:   4200, // Set other attributes as needed
  HttpOnly: true,
  Secure:   false,
  SameSite: http.SameSiteNoneMode,
})
session.Set("sessionId", id)
err = session.Save()
if err != nil {
    c.AbortWithError(http.StatusInternalServerError, err)
    return
}

c.Status(http.StatusCreated)

问题原因

核心问题出在HttpOnly Cookie的特性:后端设置了HttpOnly: true,这意味着该Cookie只能由浏览器在HTTP请求中自动携带,无法通过前端JavaScript的document.cookie读取。你的CookieService正是依赖document.cookie来获取Cookie值,所以自然返回null。

解决方案

方案1:后端提供验证会话状态的接口(推荐)

HttpOnly Cookie是安全最佳实践,不建议关闭。正确的做法是后端提供一个接口,比如/api/auth/check-session,前端调用该接口验证会话是否有效:

  1. 后端实现会话验证接口:
func CheckSession(c *gin.Context) {
    session := sessions.Default(c)
    sessionId := session.Get("sessionId")
    if sessionId != nil {
        c.JSON(http.StatusOK, gin.H{"authenticated": true})
        return
    }
    c.JSON(http.StatusUnauthorized, gin.H{"authenticated": false})
}
  1. 修改Angular的AuthService:
    将isAuthenticated改为异步方法,调用后端验证接口:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, map } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  constructor(private http: HttpClient) {}

  authRequest(url: string, User: object ) {
    return this.http.post(url, User, {observe: 'response', withCredentials: true });
  };

  isAuthenticated(): Observable<boolean> {
    return this.http.get<{authenticated: boolean}>('/api/auth/check-session', {withCredentials: true})
      .pipe(map(res => res.authenticated));
  }
}
  1. 修改AuthGuard适配异步验证:
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable, map } from 'rxjs';
import { AuthService } from './auth.service';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(
    private auth: AuthService,
    private router: Router
  ) {}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean | UrlTree> {
    return this.auth.isAuthenticated().pipe(
      map(authenticated => {
        if (authenticated) {
          return true;
        } else {
          console.error('User is not authenticated');
          return this.router.createUrlTree(['/signin']);
        }
      })
    );
  }
}

方案2:关闭HttpOnly(不推荐)

如果只是测试环境临时验证,可以将后端Cookie的HttpOnly改为false,这样前端就能通过document.cookie读取到sessionId。但生产环境绝对不建议这么做,会增加XSS攻击风险:

session.Options(sessions.Options{
  // ...其他配置
  HttpOnly: false,
})

补充说明

  • 确保前端请求后端接口时都带上withCredentials: true,这样浏览器才会自动携带HttpOnly Cookie。
  • 检查Cookie的SameSite和Domain配置是否正确,避免跨域场景下Cookie无法正常携带。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 04:44:53