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 ]

成功了!