2016-11-28 17 views
8

Próbuję zaimplementować "Autoryzację opartą na rolach" za pomocą IdentityServer4, aby umożliwić dostęp do mojego interfejsu API na podstawie ról użytkownika.Autoryzacja na podstawie ról za pomocą IdentityServer4

Na przykład chcę mieć dwie role dla użytkownika, tj. FreeUser i PaidUser i chcę umożliwić dostęp do interfejsu API poprzez atrybut Authorize za pomocą [Authorize (Roles = "FreeUser"))], Uprzejmie pomóżcie mi, jak mogę to osiągnąć.

Mam następującą strukturę rozwiązanie:

  1. IdentityServer
  2. WebAPI
  3. JavaScript Client

Zarejestrowałem mojego klienta Javascript następująco:

new Client 
      { 
       ClientId = "js", 
       ClientName = "javascript client", 
       AllowedGrantTypes = GrantTypes.Implicit, 
       AllowAccessTokensViaBrowser= true, 
       RedirectUris = {"http://localhost:5004/callback.html"}, 
       PostLogoutRedirectUris = {"http://localhost:5004/index.html"}, 
       AllowedCorsOrigins = {"http://localhost:5004"}, 

       AllowedScopes = 
       { 
        StandardScopes.OpenId.Name, 
        StandardScopes.Profile.Name, 
        "api1", 
        "role", 
        StandardScopes.AllClaims.Name 
       } 
      } 

Celownik

return new List<Scope> 
     { 
      StandardScopes.OpenId, 
      StandardScopes.Profile, 

      new Scope 
      { 
       Name = "api1", 
       Description = "My API" 
      }, 
      new Scope 
      { 
       Enabled = true, 
       Name = "role", 
       DisplayName = "Role(s)", 
       Description = "roles of user", 
       Type = ScopeType.Identity, 
       Claims = new List<ScopeClaim> 
       { 
        new ScopeClaim("role",false) 
       } 
      }, 
      StandardScopes.AllClaims 
     }; 

Użytkownicy

return new List<InMemoryUser> 
     { 
      new InMemoryUser 
      { 
       Subject = "1", 
       Username = "alice", 
       Password = "password", 

       Claims = new List<Claim> 
       { 
        new Claim("name", "Alice"), 
        new Claim("website", "https://alice.com"), 
        new Claim("role","FreeUser") 
       } 
      }, 
      new InMemoryUser 
      { 
       Subject = "2", 
       Username = "bob", 
       Password = "password", 

       Claims = new List<Claim> 
       { 
        new Claim("name", "Bob"), 
        new Claim("website", "https://bob.com"), 
        new Claim("role","PaidUser") 
       } 
      } 
     }; 

WebAPI Startup.cs

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


     JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); 
     app.UseCors("default"); 
     app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions 
     { 
      Authority = "http://localhost:5000", 
      ScopeName = "api1", 
      // AdditionalScopes = new List<string> { "openid","profile", "role" }, 
      RequireHttpsMetadata = false 
     }); 

     app.UseMvc(); 
    } 

Sterownik Web Api

namespace Api.Controllers 
{ 
[Route("[controller]")] 

public class IdentityController : ControllerBase 
{ 
    [HttpGet] 
    [Authorize(Roles = "PaidUser")] 
    public IActionResult Get() 
    { 
     return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); 
    } 

    [Authorize(Roles = "FreeUser")] 
    [HttpGet] 
    [Route("getfree")] 
    public IActionResult GetFreeUser() 
    { 
     return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); 
    } 
} 
} 

JavaScript Client app.js Tutaj staram się zalogować użytkownika przez IdentityServer i złożyć żądanie API.

var mgr = new Oidc.UserManager(config); 
mgr.getUser().then(function (user) { 
if (user) { 
    log("User logged in", user.profile); 
} else { 
    log("User is not logged in."); 
} 
}); 

function login() { 
    mgr.signinRedirect(); 
} 

function api() { 
mgr.getUser().then(function (user) { 
    var url = "http://localhost:5001/identity/getfree"; 

    var xhr = new XMLHttpRequest(); 
    xhr.open("GET", url); 
    xhr.onload = function() { 
     log(xhr.status, JSON.parse(xhr.responseText)); 
    }; 

    xhr.setRequestHeader("Authorization", "Bearer " + user.access_token); 
    xhr.send(); 
    }); 
} 

function logout() { 
    mgr.signoutRedirect(); 
} 

Proces logowania działa poprawnie i mogę z powodzeniem zalogować się i mogę otrzymać rolę w tokenie dostępu.

enter image description here

Kiedy złożyć wniosek do API, klikając przycisk (wywołanie API), a następnie pojawia się następujący błąd .. enter image description here

Odpowiedz

5

Zakładając, że nie posiadasz obiektu config dla klienta javascript, zakładam, że masz skonfigurowany zakres w następujący sposób.

scope:"openid profile api1 role" 

Uważam, że główną przyczyną problemu jest to, że roszczenie rola nie jest wliczone w tokenu dostępu.

Dodaj roszczenie do zakresu api1 w następujący sposób, aby uwzględnić go w tokenie dostępu.

   new Scope 
       { 
        Name = "api1", 
        DisplayName = "API1 access", 
        Description = "My API", 
        Type = ScopeType.Resource, 
        IncludeAllClaimsForUser = true, 
        Claims = new List<ScopeClaim> 
        { 
         new ScopeClaim(ClaimTypes.Name), 
         new ScopeClaim(ClaimTypes.Role) 
        } 
       } 

Możesz przeczytać moją odpowiedź tutaj, aby pomóc w debugowaniu problemu. implementing roles in identity server 4 with asp.net identity

Kompletne rozwiązanie robocze jest tutaj. https://github.com/weliwita/IdentityServer4.Samples/tree/40844310

+0

świetny ... teraz działa dobrze .. Nie mogę uwierzyć, jak zapomniałem dodać to do Scopes. i tak dzięki. –

+0

@muhammadwaqas Myślę, że powinieneś zaakceptować odpowiedź – Learner

2

Zmień new Claim("role","FreeUser") do new Claim(ClaimTypes.Role, "FreeUser")

lub utworzyć polisa taka jak ta:

services.AddAuthorization(options => 
{ 
    options.AddPolicy("FreeUser", policy => policy.RequireClaim("role", "FreeUser")); 
}); 

i nas e:

Authorize[(Policy = "FreeUser")] 
+0

Dziękuję za odpowiedź, próbowałem obu metod, ale wynik jest taki sam, w przypadku dodawania zasad podczas tworzenia żądania interfejsu API, wysyła on dwa żądania do interfejsu API, pierwszy z nich mówi 204 [Brak zawartości] status kod, podczas gdy drugi zostaje odrzucony z 403. W przypadku roszczeń wynik jest ponownie taki sam 403 ... czy jest coś, czego mi brakuje? .. –