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 ], ... })
测试验证
现在来验证整个流程:
- 启动Django服务:
python manage.py runserver,确保之前创建了超级用户(python manage.py createsuperuser) - 启动Angular服务:
ng serve,访问http://localhost:4200 - 输入超级用户的用户名和密码,点击登录
- 打开浏览器的开发者工具(F12),切换到Application标签,查看Cookies -> http://localhost:8000,应该能看到
sessionid这个Cookie - 同时控制台会打印登录成功和用户信息,说明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
相关产品推荐
相关产品推荐

