4

Ich benutze Asp.net Core rc2 mit OpenIdConnectServer. Ich benutze angular 1.x mit augular-oauth2. Nach ein paar Tagen hat mein Fehler abgeschweift zuAsp.net Kern-Token basierte Ansprüche Authentifizierung mit OpenIdConnect und angularjs: Bearer wurde verboten

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. 

Mein ConfigureServices besteht aus

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

Meine configure Attribut als

auf Controller definiert ist

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); 
      }); 

Mein authorise hat

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

Ich speichere das Token als Cookie und füge es an Anfragen mit einem http-Interceptor in eckig an.

ich erzeugen das Token mit

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); 
      } 
     } 

ich die letzten drei Tage auf dieses Problem verbracht habe und ich merke, dass ich an dieser Stelle bin wahrscheinlich etwas offensichtlich wegen des Mangels an Schlaf fehlt. Jede Hilfe wäre willkommen.

+0

Welche Dotnet-Kernbaugruppe enthält die Erweiterungsmethode UseOpenIdConnectServer – schmidlop

Antwort

4

Der Fehler Sie sehen, wird durch zwei Faktoren wahrscheinlich verursacht:

  • Sie kein explizites Ziel Ihrer benutzerdefinierten role Anspruch Befestigung so wird es nie im Zugriffstoken serialisiert werden. Sie finden weitere Informationen zu diesem Sicherheitsmerkmal on this other SO post.

  • policy.RequireClaim("role"); möglicherweise nicht OTB arbeiten, da IdentityModel eine interne Zuordnung verwendet, das konvertiert bekannte JWT ihre ClaimTypes äquivalent behauptet: Hier wird wahrscheinlich durch rolehttp://schemas.microsoft.com/ws/2008/06/identity/claims/role (ClaimTypes.Role) ersetzt werden. Ich würde stattdessen policy.RequireRole("user") empfehlen.

Es ist auch erwähnenswert, dass manuell die client_id Speicherung nicht notwendig ist, wie es bereits für Sie durch die OpenID Connect-Server Middleware fertig ist.

Sie können es unter Verwendung ticket.GetPresenters() abrufen, das die Liste der autorisierten Präsentatoren (hier die Client-ID) zurückgibt. Beachten Sie, dass auch automatisch sichergestellt wird, dass ein Aktualisierungs-Token für einen Client A nicht von einem Client B verwendet werden kann. Sie müssen diese Überprüfung also nicht in Ihrem eigenen Code durchführen.