Я пытаюсь разработать проект django / angular и использую базовую модель пользователя для django пользователя. Я пытался реализовать аутентификацию JWT в обе стороны. На django стороне я использую библиотеку rest_framework_jwt.
Я проверил поток токенов с клиентской стороны на серверную. На простой странице входа в систему на angular я использую свое имя пользователя и пароль для входа в систему. Он принимает мои данные и перенаправляет меня на главную страницу, где я использую сервис для получения «фида» данных со стороны сервера. На этом этапе это дает мне ошибку 403. Кстати, когда я использую Postman для проверки scener ios, я добавляю jwt в качестве заголовка авторизации, такого как «JWT», и он все еще дает мне «Учетные данные аутентификации не были предоставлены». Жду ваших подсказок. Спасибо.
django -> settings.py middleware;
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 -> settings 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
}
с использованием classi c urls.py (его и включенная часть, поэтому он начинается с api / auth /)
urlpatterns = [
path('login/', obtain_jwt_token),
path('refresh-token/', refresh_jwt_token),
]
в начале, у меня есть перехватчик, authservice и feedservice
authservice
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);
}
}
}
feedservice
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);
}
);
}
}