我正在使用带有.Net Core 2.0和Asp.Net核心身份的IdentityServer4(v2.2.1)。 我的解决方案中有三个项目。
我正在尝试在我的Web API上实现基于角色的授权,以便任何客户端都可以将访问令牌传递给Web API以访问资源。
目前我可以在MVC应用程序控制器上实现Roles base授权,但我无法为WEB API Controller传递/配置相同的内容。
以下是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 使用此文件将角色添加到Identity。
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(&#34; http://localhost:5001/user&#34;);
[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 });
}