简体   繁体   English

基于Asp.net核心令牌的OpenIdConnect和angularjs声明身份验证:Bearer被禁止

[英]Asp.net core token based claims authentication with OpenIdConnect and angularjs: Bearer was forbidden

I'm using Asp.net core rc2 with OpenIdConnectServer. 我正在使用Asp.net核心rc2和OpenIdConnectServer。 I'm using angular 1.x with augular-oauth2. 我正在使用带有augular-oauth2的角度1.x. 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.

My ConfigureServices consists of 我的ConfigureServices包括

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

My configure has 我的配置有

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属性在Controller上定义为

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

I store the token as a cookie and attach it to requests using an http interceptor in angular. 我将令牌存储为cookie并使用角度的http拦截器将其附加到请求。

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. 您没有将自定义目标附加到自定义role声明中,因此它永远不会在访问令牌中序列化。 You can find more information about this security feature on this other SO post . 您可以在此SO帖子上找到有关此安全功能的更多信息。

  • 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 ). 可能无法工作OTB,因为IdentityModel使用内部映射将已知的JWT声明转换为其ClaimTypes等效声明:此处, role可能会被http://schemas.microsoft.com/ws/2008/06/identity/claims/role取代http://schemas.microsoft.com/ws/2008/06/identity/claims/roleClaimTypes.Role )。 I'd recommend using policy.RequireRole("user") instead. 我建议改用policy.RequireRole("user")

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. 值得注意的是,手动存储client_id不是必需的,因为它已经由OpenID Connect服务器中间件为您完成。

You can retrieve it using ticket.GetPresenters() , that returns the list of authorized presenters (here, the client identifier). 您可以使用ticket.GetPresenters()检索它,它返回授权演示者列表(此处为客户端标识符)。 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. 请注意,它还会自动确保发送给客户端A的刷新令牌不能被客户端B使用,因此您无需在自己的代码中执行此操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM