基于Asp.net核心令牌的声明使用OpenIdConnect和angularjs进行身份验证:禁止承载 [英] Asp.net core token based claims authentication with OpenIdConnect and angularjs: Bearer was forbidden

查看:126
本文介绍了基于Asp.net核心令牌的声明使用OpenIdConnect和angularjs进行身份验证:禁止承载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将Asp.net core rc2与OpenIdConnectServer一起使用.我正在使用augular-oauth2的angular1.x.几天后,我的错误已经转移到

I'm using Asp.net core rc2 with OpenIdConnectServer. I'm using angular 1.x with augular-oauth2. After a few days, my error has digressed to

Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:54275/api/Account/Username  
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: Successfully validated the token.
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: HttpContext.User merged via AutomaticAuthentication from authenticationScheme: Bearer.
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: AuthenticationScheme: Bearer was successfully authenticated.
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed for user: .
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Warning: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes (Bearer).
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: AuthenticationScheme: Bearer was forbidden.

我的ConfigureServices组成

My ConfigureServices consists of

services.AddAuthorization(options =>
            {
                options.AddPolicy("UsersOnly", policy =>
                {
                    policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
                    policy.RequireClaim("role");
                });
            });

我的配置有

app.UseWhen(context => context.Request.Path.StartsWithSegments(new PathString("/api")), branch =>
            {
                branch.UseJwtBearerAuthentication(new JwtBearerOptions
                {
                    AutomaticAuthenticate = true,
                    AutomaticChallenge = true,
                    RequireHttpsMetadata = false,

                    Audience = "http://localhost:54275/",
                    Authority = "http://localhost:54275/",
                    TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidAudience = "client1",
                        //ValidAudiences = new List<string> { "", "empty", "null"}
                    }
                });
            });

            app.UseOpenIdConnectServer(options =>
            {
                options.AuthenticationScheme = OpenIdConnectServerDefaults.AuthenticationScheme;
                options.Provider = new SimpleAuthorizationServerProvider();
                options.AccessTokenHandler = new JwtSecurityTokenHandler();
                options.ApplicationCanDisplayErrors = true;
                options.AllowInsecureHttp = true;
                options.TokenEndpointPath = new PathString("/oauth2/token");
                options.LogoutEndpointPath = new PathString("/oauth2/logout");
                options.RevocationEndpointPath = new PathString("/oauth2/revoke");
                options.UseJwtTokens();
                //options.AccessTokenLifetime = TimeSpan.FromHours(1);
            });

我的授权属性在控制器上定义为

My authorize attribute is defined on the Controller as

[Authorize(Policy = "UsersOnly", ActiveAuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme), Route("api/Account")]

我将令牌存储为cookie,并使用http拦截器(以angular的形式)将其附加到请求中.

I store the token as a cookie and attach it to requests using an http interceptor in angular.

我通过以下方式生成令牌

I generate the token with

public override async Task GrantResourceOwnerCredentials(GrantResourceOwnerCredentialsContext context)
        {
            // validate user credentials (demo mode)
            // should be stored securely (salted, hashed, iterated)
            using (var con = new SqlConnection(ConnectionManager.GetDefaultConnectionString()))
            {
                if (!Hashing.ValidatePassword(context.Password, await con.ExecuteScalarAsync<string>("SELECT PassHash FROM dbo.Users WHERE Username = @UserName", new { context.UserName })))
                {
                    context.Reject(
                        error: "bad_userpass",
                        description: "UserName/Password combination was invalid."
                        );
                    return;
                }

                // create identity
                var id = new ClaimsIdentity(context.Options.AuthenticationScheme);
                id.AddClaim(new Claim("sub", context.UserName));
                id.AddClaim(new Claim("role", "user"));

                // create metadata to pass on to refresh token provider
                var props = new AuthenticationProperties(new Dictionary<string, string>
                {
                    {"as:client_id", context.ClientId}
                });
                var ticket = new AuthenticationTicket(new ClaimsPrincipal(id), props,
                    context.Options.AuthenticationScheme);
                ticket.SetAudiences("client1");
                //ticket.SetScopes(OpenIdConnectConstants.Scopes.OpenId, OpenIdConnectConstants.Scopes.Email, OpenIdConnectConstants.Scopes.Profile, "api-resource-controller");
                context.Validate(ticket);
            }
        }

我已经花了最后三天时间来解决这个问题,我意识到此时由于睡眠不足,我可能会遗漏一些明显的东西.任何帮助将不胜感激.

I've spent the last three days on this problem and I realize that at this point I'm probably missing something obvious due to lack of sleep. Any help would be appreciated.

推荐答案

您看到的错误可能是由两个因素引起的:

The error you're seeing is likely caused by 2 factors:

  • You're not attaching an explicit destination to your custom role claim so it will never be serialized in the access token. You can find more information about this security feature on this other SO post.

policy.RequireClaim("role");可能不适用于OTB,因为IdentityModel使用内部映射将著名的JWT声明转换为等效的ClaimTypes:在这里,role可能会替换为http://schemas.microsoft.com/ws/2008/06/identity/claims/role().我建议改用policy.RequireRole("user").

policy.RequireClaim("role"); might not work OTB, as IdentityModel uses an internal mapping that converts well-known JWT claims to their ClaimTypes equivalent: here, role will be likely replaced by http://schemas.microsoft.com/ws/2008/06/identity/claims/role (ClaimTypes.Role). I'd recommend using policy.RequireRole("user") instead.

还有一点值得注意,因为OpenID Connect服务器中间件已经为您完成了client_id的手动存储.

It's also worth noting that manually storing the client_id is not necessary as it's already done for you by the OpenID Connect server middleware.

您可以使用ticket.GetPresenters()检索它,它返回授权演示者的列表(此处为客户标识符).请注意,它还会自动确保客户端B不会使用发布给客户端A的刷新令牌,因此您不必在自己的代码中进行此检查.

You can retrieve it using ticket.GetPresenters(), that returns the list of authorized presenters (here, the client identifier). Note that it also automatically ensures a refresh token issued to a client A can't be used by a client B, so you don't have to do this check in your own code.

这篇关于基于Asp.net核心令牌的声明使用OpenIdConnect和angularjs进行身份验证:禁止承载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆