RXJS映射运算符返回空响应

时间:2018-07-04 14:03:20

标签: asp.net angular authentication asp.net-core rxjs

首先,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变为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

1 个答案:

答案 0 :(得分:0)

嗯,这里有几个问题。 首先,我的Chrome版本破坏了VS Studio调试器。我必须将其更新到63+版本(以我的情况为65) https://social.msdn.microsoft.com/Forums/vstudio/en-US/5cd1aa58-d986-4d03-a10e-bf1fd62080a7/simultaneous-debugging-in-chrome?forum=vsdebug#5cd1aa58-d986-4d03-a10e-bf1fd62080a7

此后,我可以进行更好的调试,然后发现错误。

1- auth.service.ts。 throwError中的Observable函数 https://www.academind.com/learn/javascript/rxjs-6-what-changed/

return this.http.post<TokenResponse>(url, data)
        .pipe(
            map(res => {
                let token = res && res.token;
                if (token) {
                    this.setAuth(res);
                    return true;
                }
                else {
                    //failed login
                    return Observable.throwError('Unauthorized');
                }

            }),
            catchError(error => {
                //console.log(error);
                return new Observable<any>(error);
            })
        );

2- TokenController Audiecnete而非Audience中的Typo错误

            var token = new JwtSecurityToken(
                    issuer: Configuration["Auth:Jwt:Issuer"],
                    audience: Configuration["Auth:Jwt:Audience"],
                    claims: claims,
                    notBefore: now,
                    expires:
                        now.Add(TimeSpan.FromMinutes(tokenExpirationMins)),
                    signingCredentials: new SigningCredentials(issuerSigningKey, SecurityAlgorithms.HmacSha256)
                );