【发布时间】:2018-12-13 00:09:49
【问题描述】:
首先,package.json:
"@angular/cli": "^6.0.8",
"rxjs": "6.2.1",
我正在关注带有角度教程的 asp.net core 2。我不得不修改一些代码,因为它被认为是旧版本。
本章是关于创建 JWT 身份验证的。
我得到了不记名令牌,但是当 api controller 返回响应时,auth.service 得到一个空响应,并且 let token = res && res.token; 行对于 if 变为 false,因此它永远不会被识别。
我怀疑 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
【问题讨论】:
-
你检查过你的实际反应了吗?
-
@AlexRiabov 是的,我得到了一个有效的 json 对象。我编辑了显示我使用邮递员测试的响应的问题
-
您是否尝试捕获应用程序对请求的响应?例如。在 Chrome 中的 DevTools 中
-
另外,在
token行之前添加了console.log(res)以查看res是否真的为空,但没关系:Object {token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4Z…kvIn0.KXJ_SmrqhJF1oclEUcI05F7-S4DSLHVDz-R6fRVKwt8", expiration: 86400}这就是为什么我认为它与转换和 TokenResponse 接口,但属性名称和数据类型匹配 -
您在控制台中看到
Unauthorized吗?
标签: asp.net angular authentication asp.net-core rxjs