Я новичок в JWT, и я благодарю вас за ваше терпение.
Я генерирую jwt в PHP со следующим:
// Create token header as a JSON string
$header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']);
// Create token payload as a JSON string
$payload = json_encode(['username' => $this->username, 'password' => $this->password]);
// Encode Header to Base64Url String
$base64UrlHeader = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
// Encode Payload to Base64Url String
$base64UrlPayload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload));
// Create Signature Hash
$signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlPayload, '<big secret>', true);
// Encode Signature to Base64Url String
$base64UrlSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));
Все это было просто для генерации подписи - $ base64UrlSignature - которая затем устанавливается на ключ:
$ this-> key = $ base64UrlSignature;
$token = array(
"iss" => $this->iss,
"aud" => $this->aud,
"iat" => $this->iat,
"nbf" => $this->nbf,
"data" => array(
"username" => $this->username,
"password" => $this->password
)
);
// generate jwt
$this->jwt = JWT::encode($token, $this->key);
echo json_encode(
array(
"status" => 401,
"id" => 0,
"uName" => "Guest",
"isAdmin" => "0",
"ts" => "2018-12-28 00:00:00",
"loggedIn" => false,
"msg" => "Combination of username and password not found",
"jwt" => $this->jwt
)
);
У меня вопрос: нужно ли делать то же самое на стороне клиента в Angular, чтобы посмотреть, совпадает ли это с тем, что генерируется сервером?
Пока все, что я прочитал, связано с сервером, генерирующим jwt, тогда в Angular сделайте следующее:
localStorage.setItem("jwt", res.jwt);
Просто поместите в локальное хранилище. Это все, что нужно?
Не должно ли быть сравнение токена, сгенерированного сервером, с токеном, сгенерированным клиентом?
Если так, то как мне перевести приведенный выше код для этого? Например, что в Angular эквивалентно классу Google jwt PHP:
$this->jwt = JWT::encode($token, $this->key);
Я добавляю код в исходное сообщение. Вот перехватчик, который я сделал:
import { ShoppingCartValuesService } from "./shopping-cart-values.service";
import { Injectable, Injector } from "@angular/core";
import {
HttpEvent,
HttpInterceptor,
HttpHandler,
HttpRequest
} from "@angular/common/http";
import { Observable } from "rxjs/";
import * as jwt_decode from "jwt-decode";
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(public srvc: ShoppingCartValuesService) {}
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const idToken = localStorage.getItem("jwt");
if (idToken) {
const cloned = req.clone({
headers: req.headers.set("Authorization", "Bearer " + idToken)
});
console.log("Decoded jwt token: ", this.getDecodedAccessToken(idToken));
return next.handle(cloned);
} else {
return next.handle(req);
}
}
getDecodedAccessToken(token: string): any {
try {
return jwt_decode(token);
} catch (error) {
console.log("error: ", error);
return false;
}
}
}
Который вызывается каждый раз, когда в ссылках навигационной панели делается щелчок с помощью обработчика щелчка checkRequest (), который проходит маршрут и позже добавляет весь URL:
<li class="nav-item">
<a
class="nav-link"
data-toggle="tooltip"
title="Products"
routerLink="/products"
id="products"
(click)="checkRequest('/products')"
><span>Products</span></a
>
</li>
Еще раз изменив сообщение, чтобы отобразить результат console.log из (click) = "checkRequest ('/ products');
Метод CheckRequest:
checkRequest(url) {
const newUrl = this.srvc.serverBase + url;
this.clickResponse = this.http.get(newUrl, { observe: "body" });
console.log(
"newUrl: " +
newUrl +
" this.clickResponse: " +
JSON.stringify(this.clickResponse)
);
}
Из console.log при нажатии на ссылку «/ products»:
newUrl: http://local.kronus:8001/products this.clickResponse: {"_isScalar":false,"source":{"_isScalar":false,"source":{"_isScalar":false,"source":{"_isScalar":true,"value":{"url":"http://local.kronus:8001/products","body":null,"reportProgress":false,"withCredentials":false,"responseType":"json","method":"GET","headers":{"normalizedNames":{},"lazyUpdate":null,"headers":{}},"params":{"updates":null,"cloneFrom":null,"encoder":{},"map":null},"urlWithParams":"http://local.kronus:8001/products"}},"operator":{"concurrent":1}},"operator":{}},"operator":{}}
Перехватчик, похоже, ничего не производит. Я что-то упустил, чтобы включить перехватчик?
Еще одно обновление: после некоторого прочтения я понял, что мне нужно ввести перехватчик в мою службу входа в систему:
private authInt: AuthInterceptor
Также я добавил в сервис входа в систему:
clickResponse: Observable<any>;
Я переместил метод checkRequest в службу входа в систему:
checkRequest(url) {
const newUrl = this.appBase + url;
return (this.clickResponse = this.http.get(newUrl, { observe: "body" }));
}
В компоненте navbar я изменил метод на следующий, вызывая checkRequest службы:
checkRequest(url) {
this.srvc.checkRequest(url).subscribe(data => {
console.log("after clicking login: ", data);
});
}
Вот ошибка 404 в консоли:
<code> HttpErrorResponse {headers: HttpHeaders, status: 404, statusText: "Not Found", url: "http://localhost:4200/login", ok: false, …}
error: "<!DOCTYPE html>↵<html lang="en">↵<head>↵<meta charset="utf-8">↵<title>Error</title>↵</head>↵<body>↵<pre>Cannot GET /login
↵ ↵ ↵»
заголовки: HttpHeaders {normalizedNames: Map (0), lazyUpdate: null, lazyInit: ƒ}
сообщение: «Http-сообщение об ошибке для http://localhost:4200/login: 404 Not Found»
имя: "HttpErrorResponse"
хорошо: ложь
статус: 404
statusText: "Not Found"
URL: "http://localhost:4200/login"
Как это возможно, что / логин не найден? Я буквально на странице входа. Это потому, что это проверено до того, как приложение войдет в страницу входа?
Это когда я понял, что мне нужно отправлять не '/ login', а uri к api, который не выдал ошибок, но также не указал jwt в заголовках. Я попытался сделать то же самое на странице admin / products, которая, кажется, в следующей строке просто возвращает полезную нагрузку, полученную от API:
return (this.clickResponse = this.http.get(newUrl, { observe: "body" }));
Тем не менее, я не вижу в разделе заголовков ничего, что передавал бы jwt Authorization Bearer. Чего мне не хватает?
Заранее спасибо