Is there any existing Keycloak client for Asp.net Core? I have found a NuGet package for .net but it doesn\'t work with Core. Do you have any ideas how to easily integrate w
I've played a bit with this today. The most straightforward way is too use OpenId standard.
In Startup.cs I used OpenIdConnect Authentication:
public void Configure(...)
{ (...)
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme,
AutomaticAuthenticate = true,
CookieHttpOnly = true,
CookieSecure = CookieSecurePolicy.SameAsRequest
});
app.UseOpenIdConnectAuthentication(CreateKeycloakOpenIdConnectOptions());`(...)
}`
OpenIdConnectOptions method:
private OpenIdConnectOptions CreateKeycloakOpenIdConnectOptions()
{
var options = new OpenIdConnectOptions
{
AuthenticationScheme = "oidc",
SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme,
Authority = Configuration["Authentication:KeycloakAuthentication:ServerAddress"]+"/auth/realms/"+ Configuration["Authentication:KeycloakAuthentication:Realm"],
RequireHttpsMetadata = false, //only in development
PostLogoutRedirectUri = Configuration["Authentication:KeycloakAuthentication:PostLogoutRedirectUri"],
ClientId = Configuration["Authentication:KeycloakAuthentication:ClientId"],
ClientSecret = Configuration["Authentication:KeycloakAuthentication:ClientSecret"],
ResponseType = OpenIdConnectResponseType.Code,
GetClaimsFromUserInfoEndpoint = true,
SaveTokens = true
};
options.Scope.Add("openid");
return options;
}
In appsettings.json add configuration for Keycloak:
{
(...),
"Authentication": {
"KeycloakAuthentication": {
"ServerAddress": "http://localhost:8180",
"Realm": "demo",
"PostLogoutRedirectUri": "http://localhost:57630/",
"ClientId": "KeycloakASPNETCore",
"ClientSecret": "secret-get-it-in-keycloakConsole-client-credentials"
}
}
}
Keycloak client is configuerd as followed:
If I want to Authorize user by role I do something like this:
Add authorization by claims in ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
(...)
services.AddAuthorization(options =>
{
options.AddPolicy("Accounting", policy =>
policy.RequireClaim("member_of", "[accounting]")); //this claim value is an array. Any suggestions how to extract just single role? This still works.
});
}
I've edited get method in ValuesController (Default Web API template):
[Authorize(Policy = "Accounting")]
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public Dictionary Get()
{
var userPrinciple = User as ClaimsPrincipal;
var claims = new Dictionary();
foreach (var claim in userPrinciple.Claims)
{
var key = claim.Type;
var value = claim.Value;
claims.Add(key, value);
}
return claims;
}
If I login with user that has accounting role or is in group that has accounting role, it should display my user claims on address localhost:57630/api/values.
I hope this works for you.
Edit: .NET Core 2 Hi everyone! The way my app works changed quite a bit and I have not fully tested .NET Core 2 yet, but you can still try connecting to Keycloak like this in ConfigureServices:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = Configuration["Authentication:KeycloakAuthentication:ServerAddress"] + "/auth/realms/" + Configuration["Authentication:KeycloakAuthentication:Realm"];
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidAudiences = new string[] { "curl", "financeApplication", "accountingApplication", "swagger"}
};
options.RequireHttpsMetadata = false; //for test only!
options.SaveToken = true;
options.Validate();
});
And in Configure:
app.UseAuthentication();
You can access your token later with IHttpContextAccessor httpContextAccessor, for example:
public KeycloakAuthorizationRequirementHandler(IConfiguration config,
IHttpContextAccessor httpContextAccessor,
IMemoryCache memoryCache)
{
_config = config;
_httpContextAccessor = httpContextAccessor;
_memoryCache = memoryCache;
}
//get accessToken
var accessToken = _httpContextAccessor.HttpContext.GetTokenAsync("access_token");
_httpContextAccessor.HttpContext.Items["username"] = username;
Tell me how it goes.