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

Django REST Framework向Angular传递Session Key存为Cookie完整示例求助

嘿,我太懂你这种卡了好几天的憋屈了!这就给你一个从头到尾的完整示例,手把手解决Django REST Framework(DRF)和Angular之间的Session Cookie传递与保存问题。

Django 端配置

首先搞定Django这边的跨域和Session设置,这是核心前提:

1. 安装并配置CORS插件

因为你的Angular跑在4200,Django在8000,属于跨域请求,必须配置CORS允许携带凭证:

  • 先安装django-cors-headers:
    pip install django-cors-headers
    
  • 修改settings.py:
    # INSTALLED_APPS里添加
    INSTALLED_APPS = [
        ...
        'corsheaders',
        'rest_framework',
        ...
    ]
    
    # MIDDLEWARE里必须放在CommonMiddleware之前
    MIDDLEWARE = [
        'corsheaders.middleware.CorsMiddleware',
        'django.middleware.common.CommonMiddleware',
        ...
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        ...
    ]
    
    # 允许携带凭证(关键!)
    CORS_ALLOW_CREDENTIALS = True
    
    # 允许的来源,不能用通配符*,必须指定具体的Angular地址
    CORS_ALLOWED_ORIGINS = [
        "http://localhost:4200",
    ]
    
    # Session Cookie配置
    SESSION_COOKIE_DOMAIN = "localhost"  # 本地开发用localhost
    SESSION_COOKIE_SAMESITE = "Lax"  # 本地http环境用Lax,https环境可以设为None(但需要Secure)
    SESSION_COOKIE_SECURE = False  # 本地http要设为False,https才设为True
    

2. 配置DRF的认证方式

让DRF支持Session认证,修改settings.py:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
        # 如果你还需要Token认证可以加上,但这里先聚焦Session
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ]
}

3. 编写测试用的API视图

写几个简单的视图来测试登录和Session验证:

# 在app的views.py里
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from django.contrib.auth import authenticate, login, logout
from django.http import JsonResponse

@api_view(['POST'])
def login_view(request):
    username = request.data.get('username')
    password = request.data.get('password')
    user = authenticate(request, username=username, password=password)
    if user is not None:
        login(request, user)
        return Response({'message': '登录成功'}, status=200)
    return Response({'error': '用户名或密码错误'}, status=401)

@api_view(['POST'])
def logout_view(request):
    logout(request)
    return Response({'message': '退出成功'}, status=200)

@api_view(['GET'])
@permission_classes(['rest_framework.permissions.IsAuthenticated'])
def user_info(request):
    return Response({
        'username': request.user.username,
        'email': request.user.email
    })

4. 配置URL路由

在项目的urls.py里添加:

from django.urls import path
from your_app_name.views import login_view, logout_view, user_info

urlpatterns = [
    ...
    path('api/login/', login_view, name='login'),
    path('api/logout/', logout_view, name='logout'),
    path('api/user-info/', user_info, name='user-info'),
]
Angular 端配置

接下来处理Angular这边的请求配置,确保能携带Session Cookie:

1. 配置HttpClient的全局拦截器(推荐)

创建一个拦截器,让所有请求自动带上withCredentials: true,不用每个请求都手动加:

  • 生成拦截器:
    ng generate interceptor auth/auth
    
  • 修改auth.interceptor.ts:
    import { Injectable } from '@angular/core';
    import {
      HttpRequest,
      HttpHandler,
      HttpEvent,
      HttpInterceptor
    } from '@angular/common/http';
    import { Observable } from 'rxjs';
    
    @Injectable()
    export class AuthInterceptor implements HttpInterceptor {
    
      constructor() {}
    
      intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
        // 克隆请求并添加withCredentials
        const modifiedReq = request.clone({
          withCredentials: true
        });
        return next.handle(modifiedReq);
      }
    }
    
  • 在app.module.ts里注册拦截器:
    import { HTTP_INTERCEPTORS } from '@angular/common/http';
    import { AuthInterceptor } from './auth/auth.interceptor';
    
    @NgModule({
      ...
      providers: [
        {
          provide: HTTP_INTERCEPTORS,
          useClass: AuthInterceptor,
          multi: true
        }
      ],
      ...
    })
    export class AppModule { }
    

2. 编写登录和用户信息服务

创建一个Auth服务来处理登录、退出和获取用户信息:

ng generate service auth/auth

修改auth.service.ts:

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

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  private baseUrl = 'http://localhost:8000/api';

  constructor(private http: HttpClient) { }

  login(username: string, password: string): Observable<any> {
    return this.http.post(`${this.baseUrl}/login/`, { username, password });
  }

  logout(): Observable<any> {
    return this.http.post(`${this.baseUrl}/logout/`, {});
  }

  getUserInfo(): Observable<any> {
    return this.http.get(`${this.baseUrl}/user-info/`);
  }
}

3. 编写测试组件

创建一个简单的组件来测试登录流程:

ng generate component auth/login

修改login.component.ts:

import { Component } from '@angular/core';
import { AuthService } from '../auth.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent {
  username: string = '';
  password: string = '';
  userInfo: any = null;

  constructor(private authService: AuthService) { }

  onLogin(): void {
    this.authService.login(this.username, this.password).subscribe({
      next: (res) => {
        console.log('登录成功', res);
        // 登录成功后获取用户信息
        this.authService.getUserInfo().subscribe({
          next: (info) => {
            this.userInfo = info;
            console.log('用户信息', info);
          },
          error: (err) => console.error('获取用户信息失败', err)
        });
      },
      error: (err) => console.error('登录失败', err)
    });
  }

  onLogout(): void {
    this.authService.logout().subscribe({
      next: (res) => {
        console.log('退出成功', res);
        this.userInfo = null;
      },
      error: (err) => console.error('退出失败', err)
    });
  }
}

修改login.component.html:

<div>
  <input type="text" [(ngModel)]="username" placeholder="用户名">
  <input type="password" [(ngModel)]="password" placeholder="密码">
  <button (click)="onLogin()">登录</button>
  <button (click)="onLogout()" *ngIf="userInfo">退出</button>

  <div *ngIf="userInfo">
    <h3>当前用户信息</h3>
    <p>用户名: {{ userInfo.username }}</p>
    <p>邮箱: {{ userInfo.email }}</p>
  </div>
</div>

别忘了在app.module.ts里导入FormsModule,因为用了ngModel:

import { FormsModule } from '@angular/forms';

@NgModule({
  ...
  imports: [
    ...
    FormsModule
  ],
  ...
})
测试验证

现在来验证整个流程:

  1. 启动Django服务:python manage.py runserver,确保之前创建了超级用户(python manage.py createsuperuser)
  2. 启动Angular服务:ng serve,访问http://localhost:4200
  3. 输入超级用户的用户名和密码,点击登录
  4. 打开浏览器的开发者工具(F12),切换到Application标签,查看Cookies -> http://localhost:8000,应该能看到sessionid这个Cookie
  5. 同时控制台会打印登录成功和用户信息,说明Session已经生效
常见坑提醒
  • CORS_ALLOWED_ORIGINS不能用通配符:* 如果你设置了CORS_ALLOW_CREDENTIALS = True,就必须指定具体的允许来源,不能用*,否则浏览器会拒绝携带凭证
  • withCredentials必须设为true: 不管是拦截器全局设置还是单个请求设置,这个选项是让浏览器自动携带Cookie的关键
  • Session Cookie的SameSite设置: 本地http环境用Lax就够了,如果是线上https环境需要跨域的话,要设为None同时开启SESSION_COOKIE_SECURE = True
  • Django的SessionMiddleware必须在AuthenticationMiddleware之前: 这个顺序错了会导致Session无法正常工作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:50:32