Я использую IdentityServer4 (v2.2.1) с .Net Core 2.0 и Asp.Net Core Identity.
У меня есть три проекта в моем решении.
- IdentityServer
- Веб-API
- Веб-приложение MVC
Я пытаюсь внедрить Role Based Authorization в моем Web API, чтобы любой клиент передавал токен доступа в Web API для доступа к ресурсам.
В настоящее время я могу реализовать авторизацию на основе ролей на контроллере приложений MVC, но не могу передать / настроить то же самое для контроллера WEB API.
Ниже приведены файлы Identity Server:
Config.cs
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
//SCOPE - Resource to be protected by IDS
new ApiResource("TCSAPI", "TCS API")
{
UserClaims = { "role" }
}
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "TCSIdentity",
ClientName = "TCS Mvc Client Application .",
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
RequireConsent = false,
ClientSecrets =
{
new Secret("secret".Sha256())
},
RedirectUris = { "http://localhost:5002/signin-oidc" },
PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
AlwaysSendClientClaims= true,
AlwaysIncludeUserClaimsInIdToken = true,
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Email,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.OfflineAccess,
"TCSAPI",
"office",
"role",
},
AllowOfflineAccess = true
}
};
}
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new IdentityResource[]
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResources.Email(),
new IdentityResource
{
Name = "role",
DisplayName="User Role",
Description="The application can see your role.",
UserClaims = new[]{JwtClaimTypes.Role,ClaimTypes.Role},
ShowInDiscoveryDocument = true,
Required=true,
Emphasize = true
}
};
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// Add application services.
services.AddTransient<IEmailSender, EmailSender>();
services.AddMvc();
// configure identity server with in-memory stores, keys, clients and scopes
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryPersistedGrants()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddAspNetIdentity<ApplicationUser>();
}
MVC WEB APP (Авторизация на основе ролей хорошо работает для MVC WEB APP):
RoleClaimAction.cs
использование этого файла для добавления ролей в личность.
internal class RoleClaimAction : ClaimAction
{
public RoleClaimAction()
: base("role", ClaimValueTypes.String)
{
}
public override void Run(JObject userData, ClaimsIdentity identity, string issuer)
{
var tokens = userData.SelectTokens("role");
IEnumerable<string> roles;
foreach (var token in tokens)
{
if (token is JArray)
{
var jarray = token as JArray;
roles = jarray.Values<string>();
}
else
roles = new string[] { token.Value<string>() };
foreach (var role in roles)
{
Claim claim = new Claim("role", role, ValueType, issuer);
if (!identity.HasClaim(c => c.Subject == claim.Subject
&& c.Value == claim.Value))
{
identity.AddClaim(claim);
}
}
}
}
}
MVC WEB APP / Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddCors();
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ClientId = "TCSIdentity";
//HYBRID FLOW
options.ClientSecret = "secret";
options.ClaimActions.Add(new RoleClaimAction()); // <--
options.ResponseType = "code id_token token";
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("TCSAPI");
options.Scope.Add("offline_access");
//END HYBRID FLOW
options.SaveTokens = true;
options.Scope.Add("role");
options.TokenValidationParameters.NameClaimType = "name";
options.TokenValidationParameters.RoleClaimType = "role";
});
}
MVC WEB APP / HomeController.cs
этот метод действий хорошо работает с авторизацией на основе ролей, но когда я пытаюсь передать токен в Web Api для доступа к чему-либо с помощью авторизации на основе ролей, он не может авторизоваться. например
var content = await client.GetStringAsync ("http://localhost:5001/user");
[Authorize(Roles = "User")]
[Route("user")]
public async Task<IActionResult> UserAccess()
{
var tokenClient = new TokenClient("http://localhost:5000/connect/token", "RoleApi", "secret");
var tokenResponse = await tokenClient.RequestClientCredentialsAsync("TCSAPI");
var client = new HttpClient();
client.SetBearerToken(tokenResponse.AccessToken);
var content = await client.GetStringAsync("http://localhost:5001/user");
ViewBag.Json = JArray.Parse(content).ToString();
return View("json");
}
[Authorize(Roles = "Admin")]
[Route("admin")]
public async Task<IActionResult> AdminAccess()
{
var accessToken = await HttpContext.GetTokenAsync("id_token");
var client = new HttpClient();
client.SetBearerToken(accessToken);
var content = await client.GetStringAsync("http://localhost:5001/admin");
ViewBag.Json = JArray.Parse(content).ToString();
return View("json");
}
WebAPI / Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore()
.AddAuthorization()
.AddJsonFormatters();
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ApiName = "TCSAPI";
});
services.AddCors(options =>
{
options.AddPolicy("default", policy =>
{
policy.WithOrigins("http://localhost:5002")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
}
WEB API / TestController.cs
[Route("admin")]
[Authorize(Roles = "Admin")]
public IActionResult AdminAccess()
{
return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
}
[Route("user")]
[Authorize(Roles = "User")]
public IActionResult UserAccess()
{
return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
}
[AllowAnonymous]
[Route("public")]
public IActionResult PublicAccess()
{
return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
}