Сначала package.json
:
"@angular/cli": "^6.0.8",
"rxjs": "6.2.1",
Я слежу за ядром asp.net 2 с угловым уроком. Мне пришлось адаптировать некоторый код, потому что он был предназначен для более старой версии.
Глава посвящена созданию аутентификации JWT.
Я получаю токен на предъявителя, но когда api controller
возвращает ответ, auth.service
получает пустой ответ, и строка let token = res && res.token;
становится ложной для if
, поэтому он никогда не идентифицируется.
Я подозреваю, что что-то не так с приведением к TokenResponse, но я не могу понять, что.
token.response.ts
interface TokenResponse {
token: string,
expiration: number
}
auth.service.ts
import { EventEmitter, Inject, Injectable, PLATFORM_ID } from "@angular/core";
import { isPlatformBrowser } from '@angular/common';
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Observable } from "rxjs";
import { map, catchError } from 'rxjs/operators';
import 'rxjs/Rx';
@Injectable()
export class AuthService {
authKey: string = "auth";
clientId: string = "NetCoreAngularWeb";
constructor(private http: HttpClient,
@Inject(PLATFORM_ID) private platformId: any) {
}
// performs the login
login(username: string, password: string): Observable<boolean> {
var url = "api/token/auth";
var data = {
username: username,
password: password,
client_id: this.clientId,
// required when signing up with username/password
grant_type: "password",
// space-separated list of scopes for which the token is
// issued
scope: "offline_access profile email"
};
return this.http.post<TokenResponse>(url, data)
.pipe(
map(res => {
let token = res && res.token;
// if the token is there, login has been successful
if (token) {
// store username and jwt token
this.setAuth(res);
// successful login
return true;
}
// failed login
return Observable.throw('Unauthorized');
}),
catchError(error => {
return new Observable<any>(error);
})
);
}
// performs the logout
logout(): boolean {
this.setAuth(null);
return true;
}
// Persist auth into localStorage or removes it if a NULL argument is given
setAuth(auth: TokenResponse | null): boolean {
if (isPlatformBrowser(this.platformId)) {
if (auth) {
localStorage.setItem(
this.authKey,
JSON.stringify(auth));
}
else {
localStorage.removeItem(this.authKey);
}
}
return true;
}
// Retrieves the auth JSON object (or NULL if none)
getAuth(): TokenResponse | null {
if (isPlatformBrowser(this.platformId)) {
var i = localStorage.getItem(this.authKey);
if (i) {
return JSON.parse(i);
}
}
return null;
}
// Returns TRUE if the user is logged in, FALSE otherwise.
isLoggedIn(): boolean {
if (isPlatformBrowser(this.platformId)) {
return localStorage.getItem(this.authKey) != null;
}
return false;
}
}
TokenController
[HttpPost("Auth")]
public async Task<IActionResult> Auth([FromBody]TokenRequestViewModel model)
{
// return a generic HTTP Status 500 (server Error)
// if the client payload is invalid.
if (model == null) return new StatusCodeResult(500);
switch (model.grant_type)
{
case "password":
return await GetToken(model);
default:
// not supported - return a HTTP 401 (Unauthorized)
return new UnauthorizedResult();
}
}
private async Task<IActionResult> GetToken(TokenRequestViewModel model)
{
try
{
// check if there's an user with the given username
var user = await UserManager.FindByNameAsync(model.username);
// fallback to support e-mail address instead of username
if (user == null && model.username.Contains("@"))
user = await UserManager.FindByEmailAsync(model.username);
if (user == null || !await UserManager.CheckPasswordAsync(user, model.password))
{
// user does not exists or password mismatch
return new UnauthorizedResult();
}
// username & password matches: create and return the Jwt token
DateTime now = DateTime.UtcNow;
// add the registered claims for JWT (RFC7519)
// For more info, see...
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.Id),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, new DateTimeOffset(now).ToUnixTimeSeconds().ToString())
// TODO add additional claims here
};
var tokenExpirationMins = Configuration.GetValue<int>("Auth:Jwt:TokenExpirationInMinutes");
var issuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Auth:Jwt:Key"]));
var token = new JwtSecurityToken(
issuer: Configuration["Auth:Jwt:Issuer"],
audience: Configuration["Auth:Jwt:Audicnete"],
claims: claims,
notBefore: now,
expires:
now.Add(TimeSpan.FromMinutes(tokenExpirationMins)),
signingCredentials: new SigningCredentials(issuerSigningKey, SecurityAlgorithms.HmacSha256)
);
var encodedToken = new JwtSecurityTokenHandler().WriteToken(token);
// build & return the response
var response = new TokenResponseViewModel()
{
token = encodedToken,
expiration = tokenExpirationMins
};
return Json(response);
}
catch (Exception ex)
{
return new UnauthorizedResult();
}
}
РЕДАКТИРОВАТЬ - ответ, проверен POSTMAN
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJlODBiNzRkMi0xOGIwLTQ5NzUtOWUyYS0wOGJiOGJlOTUzMDEiLCJqdGkiOiIzNTkzNjVhYS02M2UyLTQ3ZGMtYjY1NC1mMDk3YWQxNjNmMzQiLCJpYXQiOiIxNTMwNzEzMzU2IiwibmJmIjoxNTMwNzEzMzU2LCJleHAiOjE1MzU4OTczNTYsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzE3NzkvIn0.6QlGCK_4ybzYEz8qaRDDotOja6x0FI0fZTxmky94S5Y",
"expiration": 86400
}
Status 200 OK
Time:11281 ms
Size:671 B
Content-Type →application/json; charset=utf-8
Date →Wed, 04 Jul 2018 14:09:21 GMT
Server →Kestrel
Transfer-Encoding →chunked
X-Powered-By →ASP.NET