首页 文章

OpenIddict与Angular2-jwt

提问于
浏览
1

我正在使用ASP.NET Core构建授权/身份验证Angular2应用程序 .
当我使用Authorize属性调用方法时,我在Visual Studio输出窗口中出现错误:

Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:50373/api/tasks/GetLatest/ text/plain 
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: Failed to validate the token eyJhbGciOiJSUzI1NiIsImtpZCI6IlJHRUVHM0FCSUJNVllHTEdQSjFSNjNRRkdHQlVKRUlHLU9ITy1QREgiLCJ0eXAiOiJKV1QifQ.eyJ1bmlxdWVfbmFtZSI6Im1hdGphei5jb2ZAb3BhbC5zaSIsIkFzcE5ldC5JZGVudGl0eS5TZWN1cml0eVN0YW1wIjoiMWVhYWE4MzktNzZlNy00NmVhLWE2NGUtYWJmNDVhNzY5YTBiIiwicm9sZSI6IkFkbWluaXN0cmF0b3JzIiwianRpIjoiM2U1NjAyMjUtMzQyNy00YmE4LTg4MzQtYzA2ZGI4NDE2NDA0IiwidXNhZ2UiOiJhY2Nlc3NfdG9rZW4iLCJzY29wZSI6WyJvcGVuaWQiLCJvZmZsaW5lX2FjY2VzcyJdLCJzdWIiOiIxIiwibmJmIjoxNDg1NzgyOTAwLCJleHAiOjE0ODU3ODQ3MDAsImlhdCI6MTQ4NTc4MjkwMCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDM3My8ifQ.IqDnWJJKRtAh0BWKcdQgg_Gm_rnarffdnq5ksqpm0m6BnslI0EZ-7CugSG0223k6_FwuU7iSCiI2Cu7O2uaUedDEOdoIwyxpaEyr6yjzT5pxw7hbMnNxmxAydEajqE3OI-C55vzK0nhv9ToS93dz_QF8MIQ5EMIJ1cGXXO9wqQQ0xLvX7o2wIlM3rYvh_OORdALBxl5byMsrtc3ZrVj-BEiYuuwrUwSU5oPlH28o_Oo030s9NGqaQNea5T3PNQAL8-qC6aIdcDLBwOYZevTGGLMxde9czk_Duc0mkp5KtsyVZ-oV3qTh-EdZxpPjttu5_5Bh-8YCDLP5AzOsyX5sbg.

Microsoft.IdentityModel.Tokens.SecurityTokenInvalidAudienceException: IDX10208: Unable to validate audience. validationParameters.ValidAudience is null or whitespace and validationParameters.ValidAudiences is null.
   at Microsoft.IdentityModel.Tokens.Validators.ValidateAudience(IEnumerable`1 audiences, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwt, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.<HandleAuthenticateAsync>d__1.MoveNext()
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: Bearer was not authenticated. Failure message: IDX10208: Unable to validate audience. validationParameters.ValidAudience is null or whitespace and validationParameters.ValidAudiences is null.
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed for user: (null).

在此之前,我登录自己并在Angular2应用程序中获取以下对象:

access_token:"eyJhbGciOiJSUzI1NiIsImtpZCI6IlJHRUVHM0FCSUJNVllHTEdQSjFSNjNRRkdHQlVKRUlHLU9ITy1QREgiLCJ0eXAiOiJKV1QifQ.eyJ1bmlxdWVfbmFtZSI6Im1hdGphei5jb2ZAb3BhbC5zaSIsIkFzcE5ldC5JZGVudGl0eS5TZWN1cml0eVN0YW1wIjoiMWVhYWE4MzktNzZlNy00NmVhLWE2NGUtYWJmNDVhNzY5YTBiIiwicm9sZSI6IkFkbWluaXN0cmF0b3JzIiwianRpIjoiM2U1NjAyMjUtMzQyNy00YmE4LTg4MzQtYzA2ZGI4NDE2NDA0IiwidXNhZ2UiOiJhY2Nlc3NfdG9rZW4iLCJzY29wZSI6WyJvcGVuaWQiLCJvZmZsaW5lX2FjY2VzcyJdLCJzdWIiOiIxIiwibmJmIjoxNDg1NzgyOTAwLCJleHAiOjE0ODU3ODQ3MDAsImlhdCI6MTQ4NTc4MjkwMCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDM3My8ifQ.IqDnWJJKRtAh0BWKcdQgg_Gm_rnarffdnq5ksqpm0m6BnslI0EZ-7CugSG0223k6_FwuU7iSCiI2Cu7O2uaUedDEOdoIwyxpaEyr6yjzT5pxw7hbMnNxmxAydEajqE3OI-C55vzK0nhv9ToS93dz_QF8MIQ5EMIJ1cGXXO9wqQQ0xLvX7o2wIlM3rYvh_OORdALBxl5byMsrtc3ZrVj-BEiYuuwrUwSU5oPlH28o_Oo030s9NGqaQNea5T3PNQAL8-qC6aIdcDLBwOYZevTGGLMxde9czk_Duc0mkp5KtsyVZ-oV3qTh-EdZxpPjttu5_5Bh-8YCDLP5AzOsyX5sbg"
expiration_date:"1485784700807"
expires_in:1800
id_token:"eyJhbGciOiJSUzI1NiIsImtpZCI6IlJHRUVHM0FCSUJNVllHTEdQSjFSNjNRRkdHQlVKRUlHLU9ITy1QREgiLCJ0eXAiOiJKV1QifQ.eyJ1bmlxdWVfbmFtZSI6Im1hdGphei5jb2ZAb3BhbC5zaSIsIkFzcE5ldC5JZGVudGl0eS5TZWN1cml0eVN0YW1wIjoiMWVhYWE4MzktNzZlNy00NmVhLWE2NGUtYWJmNDVhNzY5YTBiIiwicm9sZSI6IkFkbWluaXN0cmF0b3JzIiwic3ViIjoiMSIsImp0aSI6IjFmMTAzODI1LTAyM2ItNDAwNy05NjI3LTI4ODk0MmZmNzM5NyIsInVzYWdlIjoiaWRlbnRpdHlfdG9rZW4iLCJhdF9oYXNoIjoiRGVXaUcwbklJWXVxcW9vUVlBclQ3USIsIm5iZiI6MTQ4NTc4MjkwMCwiZXhwIjoxNDg1Nzg0MTAwLCJpYXQiOjE0ODU3ODI5MDAsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTAzNzMvIn0.WDvRzyG63Ok9ZjgbACzwSDsgA1mxndtx8klY64sPg3a_oeQE-rtd0EMyYnzp4uLTDW8uU6MEzuyZeufBE5SaRXMiXH45raH468XkPvX6qbSUjV2ZV6rER36eI_gFnnnGSQzfz0vSZE1Uq8-fCxxaGpjHLrNRuDWb7o--4t4mGfI6-MOvEY46IO6pgnD9GV9BTv-SzRjuQh7BTGvKu2ITkQVqbGiwLlHN-ilu2l8HG3vB0ewePcK_mvCkhbUz8n9R6q5BHrQm2qUXGMjHE023JBb6LPr3kS_9zGKgEhWRmMkclkNiQgHtFBjMxK2jG-8v14MLaVJx4fGS4q08OqQJjg"
refresh_token:"CfDJ8EUVTnABx9VCmidQlFBiYKJ1b8N1-ggRbkY6PYVT6xwuO-xG8KL64rVld2UhXTnirKU06W2bhPPE3MU42SOji3p69aZH-VYuQQwZzXyJE3AqCh-uFQ0_XynvVQn0o15x0ozknKhk3j1N9mIvuzzZ2Lc1L5hXUL1JdhkkOQmQ42JzDSEeDFp0fwCsdAAtXdY1Cvz1Xg-WiHP8Aco4pvkFxh7vioLGcR1xmmEALHEDePj7xrnP7dzwrCe4F9bhFyTx1MW-MW5Q2kVogMwa_yxbTm4kjmO2mbt9tjpeLT_aIkE7R78AqTLw_P5pwd-nxS_rc-U9IusBpOaabdHy6bNKppxzAq-1NQr0oOf2nJMEahcKjNTMo1ip78u05Xxl4btV_f7Pf-auX7bZ1GbaqBhIrwp6Ld2tPI1E-462r-H2ufmFfW50x_5OsFcJDBR5jXolLOfo1yNStqujo0ov6AR1g5hwVaq2luYl5z-iHtgiEvbQCVNzs5anu1qeaJp3oe0GSwZ0Z2SqFu4ewWE9clFxAmH8uFvI3wwsWEXfqHiXOYFQRf4shgA9VLPktGaQd7uafuSzMUrT_xguTaaLlzmq7MM8ODPrV2qblfXTUn3BMsWLp31ZOpg6aUpR4fTDP-LLnVQVi3NTyFuQwc0dUtpYrArI4YcC97lNFTzOgf9aHXKA8_4oBaCmXQsM-39A3ynDDfV4SSmhViKUOJ7KMmb4f-Og5cckldgbgcKEXd7tSJmZOsiu5rKymKHHIU4v94_5WK3dVwDfG-pb8vg1HQP_b06lIPYNYGve80CHLMLs2V_56pwN0sRa327DY6q5rLFRZ7An8jr7Bdc94EJLYEW-gtQf29NCM5sMwlqV9xlj3ZeR-r2fBdpVsT8IjlJD5qe6KnCY6jYQAgoDagfkIy4GjBGuJmR8L4IHrsSkzJAA6nVw"
token_type:"Bearer"

和我的启动文件:

public void ConfigureServices(IServiceCollection services)
{
    try
    {
        services.AddMvc();

        services.AddEntityFrameworkSqlServer();

        services.AddScoped<UserStore<AppUser, AppRole, AppDbContext, int, AppUserClaim, AppUserRole, AppUserLogin, AppUserToken, AppRoleClaim>, AppUserStore>();
        services.AddScoped<UserManager<AppUser>, AppUserManager>();
        services.AddScoped<RoleManager<AppRole>, AppRoleManager>();
        services.AddScoped<SignInManager<AppUser>, AppSignInManager>();
        services.AddScoped<RoleStore<AppRole, AppDbContext, int, AppUserRole, AppRoleClaim>, AppRoleStore>();

        var connection = Configuration["ConnectionStrings"];
        services.AddDbContext<AppDbContext>(options => {
            options.UseSqlServer(connection);
            options.UseOpenIddict<int>();
        });

        services
            .AddIdentity<AppUser, AppRole>()
            .AddUserStore<AppUserStore>()
            .AddUserManager<AppUserManager>()
            .AddRoleStore<AppRoleStore>()
            .AddRoleManager<AppRoleManager>()
            .AddSignInManager<AppSignInManager>()
            .AddDefaultTokenProviders();

        services.AddOpenIddict<int>()
            .AddEntityFrameworkCoreStores<AppDbContext>()
            .AddMvcBinders()
            .EnableTokenEndpoint("/API/authorization/token")
            .AllowPasswordFlow()
            .AllowRefreshTokenFlow()
            .UseJsonWebTokens()
            .AddEphemeralSigningKey()       //todo naj bi bil pravi certifikat, če odstranič to vrstico ne dela in vidiš error.
            .DisableHttpsRequirement();

        services.AddSingleton<DbSeeder>();

    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
        throw;
    }
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, DbSeeder dbSeeder)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
        {
            HotModuleReplacement = true
        });
    }
    else
    {

    }

    app.UseStaticFiles();

    app.UseIdentity();

    app.UseOpenIddict();

    //app.UseOAuthValidation();     //this works
    app.UseJwtBearerAuthentication(new JwtBearerOptions()
    {                
        Authority = "http://localhost:50373/",
        AutomaticAuthenticate = true,
        AutomaticChallenge = true,
        RequireHttpsMetadata = false
    });

    app.UseMvc();

    try
    {

        dbSeeder.SeedAsync();
    }
    catch (AggregateException e)
    {
        throw new Exception(e.ToString());
    }
}

}

网络选项卡中的开发者控制台 Headers :

Request URL:http://localhost:50373/api/tasks/GetLatest/
Request Method:GET
Status Code:302 Found
Remote Address:[::1]:50373
Response Headers
view source
Content-Length:0
Date:Mon, 30 Jan 2017 13:32:28 GMT
Location:http://localhost:50373/Account/Login?ReturnUrl=%2Fapi%2Ftasks%2FGetLatest%2F
Server:Kestrel
WWW-Authenticate:Bearer error="invalid_token", error_description="The audience is invalid"
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?RDpcT3BQSVNXZWJcdHJ1bmtcT3BQSVNXZWJcYXBpXHRhc2tzXEdldExhdGVzdFw=?=
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:sl-SI,sl;q=0.8,en-GB;q=0.6,en;q=0.4
authorization:Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IlJHRUVHM0FCSUJNVllHTEdQSjFSNjNRRkdHQlVKRUlHLU9ITy1QREgiLCJ0eXAiOiJKV1QifQ.eyJ1bmlxdWVfbmFtZSI6Im1hdGphei5jb2ZAb3BhbC5zaSIsIkFzcE5ldC5JZGVudGl0eS5TZWN1cml0eVN0YW1wIjoiMWVhYWE4MzktNzZlNy00NmVhLWE2NGUtYWJmNDVhNzY5YTBiIiwicm9sZSI6IkFkbWluaXN0cmF0b3JzIiwianRpIjoiM2U1NjAyMjUtMzQyNy00YmE4LTg4MzQtYzA2ZGI4NDE2NDA0IiwidXNhZ2UiOiJhY2Nlc3NfdG9rZW4iLCJzY29wZSI6WyJvcGVuaWQiLCJvZmZsaW5lX2FjY2VzcyJdLCJzdWIiOiIxIiwibmJmIjoxNDg1NzgyOTAwLCJleHAiOjE0ODU3ODQ3MDAsImlhdCI6MTQ4NTc4MjkwMCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDM3My8ifQ.IqDnWJJKRtAh0BWKcdQgg_Gm_rnarffdnq5ksqpm0m6BnslI0EZ-7CugSG0223k6_FwuU7iSCiI2Cu7O2uaUedDEOdoIwyxpaEyr6yjzT5pxw7hbMnNxmxAydEajqE3OI-C55vzK0nhv9ToS93dz_QF8MIQ5EMIJ1cGXXO9wqQQ0xLvX7o2wIlM3rYvh_OORdALBxl5byMsrtc3ZrVj-BEiYuuwrUwSU5oPlH28o_Oo030s9NGqaQNea5T3PNQAL8-qC6aIdcDLBwOYZevTGGLMxde9czk_Duc0mkp5KtsyVZ-oV3qTh-EdZxpPjttu5_5Bh-8YCDLP5AzOsyX5sbg
Cache-Control:no-cache
Connection:keep-alive
content-type:text/plain
Host:localhost:50373
Pragma:no-cache
Referer:http://localhost:50373/tasks
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36

我错过了什么?

Updated:

正如我在评论中所说,一定要将access_token保存到id_token本地存储:

private login(username: string, password: string)
    {
        let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
        let options = new RequestOptions({ headers: headers });

        const data = { username: username, password: password };
        Object.assign(data, {
            grant_type: "password",
            // offline_access is required for a refresh token
            scope: ['openid offline_access']
        });

        return this.http.post('api/authorization/token', this.encodeObjectToParams(data), options)
            .map(res => res.json())
            .map((tokens: AuthTokenModel) =>
            {
                localStorage.setItem('id_token', tokens.access_token);  //!!!

                return tokens;
            });
    }

因为Angular2-jwt默认使用id_token作为访问令牌 .

1 回答

  • 1

    如异常所示,您必须设置 Audience 属性:

    app.UseJwtBearerAuthentication(new JwtBearerOptions
    {                
        Authority = "http://localhost:50373/",
        Audience = "resource_server",
        AutomaticAuthenticate = true,
        AutomaticChallenge = true,
        RequireHttpsMetadata = false
    });
    

    您还必须在身份验证票证中设置资源:

    ticket.SetResources("resource_server");
    

相关问题