Keycloak client for ASP.NET Core

前端 未结 3 1214
抹茶落季
抹茶落季 2020-12-23 15:11

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

3条回答
  •  -上瘾入骨i
    2020-12-23 15:40

    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:

    • Client settings,
    • I've added 'accounting' role for test,
    • I added mapper 'member_of' of type 'User Client Role' for roles so that roles are added in the claims

    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.

提交回复
热议问题