HTTP 403 即使我已登录
HTTP 403 Even Im Logged In
我正在尝试开发 django/angular 项目并为 django 用户使用基本用户模型。
我试图在双方都实施 JWT 身份验证。在 Django 方面,我正在使用 rest_framework_jwt 库。
我检查了从 client-side 到 server-side 的令牌流。在 angular 上有一个简单的登录页面,我使用我的用户名和密码登录。它正在接受我的数据并将我重定向到主页,在那里我使用服务从 [=46= 获取 "feed" 数据].在此步骤中,它给了我 403 错误。顺便说一句,当我使用 Postman 检查场景时,我添加了 jwt 作为授权 header,比如 "JWT ",它仍然给我 "Authentication credentials were not provided"。等待你的帮助。谢谢。
django -> settings.py 中间件;
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
django -> 设置 py rest_framework ;
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATON_CLASSES':(
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
),
'NON_FIELD_ERRORS_KEY': 'global',
}
我将这些设置用于 jwt
#JWT SETTINGS
JWT_AUTH = {
'JWT_ALLOW_REFRESH': True,
'JWT_EXPIRATION_DELTA': timedelta(days=2) # datetime imported at start
}
使用经典 urls.py(它和包含的部分以 api/auth/ 开头)
urlpatterns = [
path('login/', obtain_jwt_token),
path('refresh-token/', refresh_jwt_token),
]
在前端我有一个拦截器、authservice 和 feedservice
授权服务
import { Injectable } from '@angular/core';
import { HttpClient, HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { tap, shareReplay } from 'rxjs/operators';
import * as JwtDecode from 'jwt-decode';
import * as moment from 'moment';
import { JWTPayload } from '../interfaces/JWTPayload';
// logs in and out, notifies other components with subscription
@Injectable({
providedIn: 'root'
})
export class AuthenticationService {
URL_API = 'http://localhost:80/api/auth';
constructor(private http: HttpClient) { }
private setSession(authResult) {
const token = authResult.token;
const payload = <JWTPayload>JwtDecode(token);
const expiresAt = moment.unix(payload.exp);
localStorage.setItem('token', authResult.token);
localStorage.setItem('expires_at', JSON.stringify(expiresAt.valueOf()));
}
get token(): string {
return localStorage.getItem('token');
}
login(username: string, password: string) {
return this.http.post(`${this.URL_API}/login/`, { username, password })
.pipe(tap(
response => {
console.log("API CALL RESPONSE FOR LOGIN => ", response);
this.setSession(response);
}
),
shareReplay(),
);
}
logout() {
localStorage.removeItem('token');
localStorage.removeItem('expires_at');
console.log("CIKIS YAPILDI ");
}
refreshToken() {
if (moment().isBetween(this.getExpiration().subtract(1, 'days'), this.getExpiration())) {
return this.http.post(
`${this.URL_API}/refresh-token/`,
{ token: this.token }
).pipe(
tap(response => { this.setSession(response); console.log("response for refresh token=>", response); }),
shareReplay(),
).subscribe();
}
}
getExpiration() {
const expiration = localStorage.getItem('expires_at');
const expiresAt = JSON.parse(expiration);
console.log("expires=>", moment(expiresAt).calendar());
return moment(expiresAt);
}
isLoggedIn() {
return moment().isBefore(this.getExpiration());
}
isLoggedOut() {
return !this.isLoggedIn();
}
}
拦截器
import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AuthenticationService } from '../services/authentication.service';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
// intercepts every api call and adds jwt header to call.
@Injectable({
providedIn: 'root'
})
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const token = localStorage.getItem('token');
console.log("firs token check => ", token);
if (token) {
console.log("gecerli token=> ", token)
const cloned = req.clone({
headers: req.headers.set('Authorization', 'JWT '.concat(token))
});
console.log("cloned ->", cloned.body);
return next.handle(cloned);
} else {
console.log("next.handle(req) => ", next.handle(req));
return next.handle(req);
}
}
}
饲料服务
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from "rxjs";
import { Post } from '../interfaces/Post';
@Injectable({
providedIn: 'root'
})
export class FeedService {
API_URL = 'http://localhost:80'
constructor(private httpClient: HttpClient) { }
public getFeed(): Observable<Post[]> {
return this.httpClient.get<Post[]>(`${this.API_URL}/api/feed/`);
}
public retrievePost(post_id: number): Observable<Post> {
return this.httpClient.get<Post>(`${this.API_URL}/api/feed/${post_id}`)
}
public postFeed(post: Post) {
return this.httpClient.post(`${this.API_URL}/api/feed/`, post)
}
}
最后还有登录组件
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { first } from 'rxjs/operators';
import { AuthenticationService } from '../services/authentication.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
loginForm: FormGroup
returnUrl: string
loading = false;
submitted = false;
error = '';
constructor(
private formBuilder: FormBuilder,
private authenticationService: AuthenticationService,
private router: Router,
private route: ActivatedRoute
) {
//redirect home if already logged in
if (authenticationService.isLoggedIn()) {
console.log("isLoggedIn() => already logged in")
router.navigate(['/']);
}
}
ngOnInit(): void {
this.loginForm = this.formBuilder.group({
username: ['', Validators.required],
password: ['', Validators.required]
});
//get returl url or redirect to /
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
}
//easy way to access fields
get f() { return this.loginForm.controls }
onSubmit() {
this.submitted = true;
// stop here if form is invalid
if (this.loginForm.invalid) { console.log("if code block => invalid credentials"); return; }
this.loading = true;
this.authenticationService.login(this.f.username.value, this.f.password.value)
.subscribe(
success => { console.log("succesfull login"); this.router.navigate([this.returnUrl]); },
error => {
this.error = error;
this.loading = false;
console.log("errors =>", error);
}
);
}
}
我明白了。在我的其他 api 视图中,我添加了这些行
permission_classes = [ IsAuthenticated ]
authentication_classes = [ JSONWebTokenAuthentication ]
成功了!
我正在尝试开发 django/angular 项目并为 django 用户使用基本用户模型。 我试图在双方都实施 JWT 身份验证。在 Django 方面,我正在使用 rest_framework_jwt 库。
我检查了从 client-side 到 server-side 的令牌流。在 angular 上有一个简单的登录页面,我使用我的用户名和密码登录。它正在接受我的数据并将我重定向到主页,在那里我使用服务从 [=46= 获取 "feed" 数据].在此步骤中,它给了我 403 错误。顺便说一句,当我使用 Postman 检查场景时,我添加了 jwt 作为授权 header,比如 "JWT ",它仍然给我 "Authentication credentials were not provided"。等待你的帮助。谢谢。
django -> settings.py 中间件;
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
django -> 设置 py rest_framework ;
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATON_CLASSES':(
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
),
'NON_FIELD_ERRORS_KEY': 'global',
}
我将这些设置用于 jwt
#JWT SETTINGS
JWT_AUTH = {
'JWT_ALLOW_REFRESH': True,
'JWT_EXPIRATION_DELTA': timedelta(days=2) # datetime imported at start
}
使用经典 urls.py(它和包含的部分以 api/auth/ 开头)
urlpatterns = [
path('login/', obtain_jwt_token),
path('refresh-token/', refresh_jwt_token),
]
在前端我有一个拦截器、authservice 和 feedservice
授权服务
import { Injectable } from '@angular/core';
import { HttpClient, HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { tap, shareReplay } from 'rxjs/operators';
import * as JwtDecode from 'jwt-decode';
import * as moment from 'moment';
import { JWTPayload } from '../interfaces/JWTPayload';
// logs in and out, notifies other components with subscription
@Injectable({
providedIn: 'root'
})
export class AuthenticationService {
URL_API = 'http://localhost:80/api/auth';
constructor(private http: HttpClient) { }
private setSession(authResult) {
const token = authResult.token;
const payload = <JWTPayload>JwtDecode(token);
const expiresAt = moment.unix(payload.exp);
localStorage.setItem('token', authResult.token);
localStorage.setItem('expires_at', JSON.stringify(expiresAt.valueOf()));
}
get token(): string {
return localStorage.getItem('token');
}
login(username: string, password: string) {
return this.http.post(`${this.URL_API}/login/`, { username, password })
.pipe(tap(
response => {
console.log("API CALL RESPONSE FOR LOGIN => ", response);
this.setSession(response);
}
),
shareReplay(),
);
}
logout() {
localStorage.removeItem('token');
localStorage.removeItem('expires_at');
console.log("CIKIS YAPILDI ");
}
refreshToken() {
if (moment().isBetween(this.getExpiration().subtract(1, 'days'), this.getExpiration())) {
return this.http.post(
`${this.URL_API}/refresh-token/`,
{ token: this.token }
).pipe(
tap(response => { this.setSession(response); console.log("response for refresh token=>", response); }),
shareReplay(),
).subscribe();
}
}
getExpiration() {
const expiration = localStorage.getItem('expires_at');
const expiresAt = JSON.parse(expiration);
console.log("expires=>", moment(expiresAt).calendar());
return moment(expiresAt);
}
isLoggedIn() {
return moment().isBefore(this.getExpiration());
}
isLoggedOut() {
return !this.isLoggedIn();
}
}
拦截器
import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AuthenticationService } from '../services/authentication.service';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
// intercepts every api call and adds jwt header to call.
@Injectable({
providedIn: 'root'
})
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const token = localStorage.getItem('token');
console.log("firs token check => ", token);
if (token) {
console.log("gecerli token=> ", token)
const cloned = req.clone({
headers: req.headers.set('Authorization', 'JWT '.concat(token))
});
console.log("cloned ->", cloned.body);
return next.handle(cloned);
} else {
console.log("next.handle(req) => ", next.handle(req));
return next.handle(req);
}
}
}
饲料服务
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from "rxjs";
import { Post } from '../interfaces/Post';
@Injectable({
providedIn: 'root'
})
export class FeedService {
API_URL = 'http://localhost:80'
constructor(private httpClient: HttpClient) { }
public getFeed(): Observable<Post[]> {
return this.httpClient.get<Post[]>(`${this.API_URL}/api/feed/`);
}
public retrievePost(post_id: number): Observable<Post> {
return this.httpClient.get<Post>(`${this.API_URL}/api/feed/${post_id}`)
}
public postFeed(post: Post) {
return this.httpClient.post(`${this.API_URL}/api/feed/`, post)
}
}
最后还有登录组件
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { first } from 'rxjs/operators';
import { AuthenticationService } from '../services/authentication.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
loginForm: FormGroup
returnUrl: string
loading = false;
submitted = false;
error = '';
constructor(
private formBuilder: FormBuilder,
private authenticationService: AuthenticationService,
private router: Router,
private route: ActivatedRoute
) {
//redirect home if already logged in
if (authenticationService.isLoggedIn()) {
console.log("isLoggedIn() => already logged in")
router.navigate(['/']);
}
}
ngOnInit(): void {
this.loginForm = this.formBuilder.group({
username: ['', Validators.required],
password: ['', Validators.required]
});
//get returl url or redirect to /
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
}
//easy way to access fields
get f() { return this.loginForm.controls }
onSubmit() {
this.submitted = true;
// stop here if form is invalid
if (this.loginForm.invalid) { console.log("if code block => invalid credentials"); return; }
this.loading = true;
this.authenticationService.login(this.f.username.value, this.f.password.value)
.subscribe(
success => { console.log("succesfull login"); this.router.navigate([this.returnUrl]); },
error => {
this.error = error;
this.loading = false;
console.log("errors =>", error);
}
);
}
}
我明白了。在我的其他 api 视图中,我添加了这些行
permission_classes = [ IsAuthenticated ]
authentication_classes = [ JSONWebTokenAuthentication ]
成功了!