Keycloak client for ASP.NET Core

前端 未结 3 1204
抹茶落季
抹茶落季 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条回答
  • 2020-12-23 15:39

    The thing that worked for us was setting these things in Startup.cs (it's cookie based authentication):

    public void Configure(...)
    {
        (...)
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme,
            AutomaticAuthenticate = true,
            CookieHttpOnly = true,
            CookieSecure = CookieSecurePolicy.SameAsRequest
        });
    
        app.UseOpenIdConnectAuthentication(CreateOpenIdConnectOptions(_customConfig));
        (...)
    }
    

    And setting up the options:

    private OpenIdConnectOptions CreateOpenIdConnectOptions(CustomConfigurationFile configuration)
    {
        var options = new OpenIdConnectOptions
        {
            AuthenticationScheme = "oidc",
            SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme,
            Authority = configuration.ServerAddress + "/auth/realms/" + configuration.Realm,
            RequireHttpsMetadata = true,
            PostLogoutRedirectUri = configuration.SystemAddress,
            ClientId = configuration.ClientId,
            ClientSecret = configuration.ClientSecret,
            ResponseType = OpenIdConnectResponseType.Code,
            GetClaimsFromUserInfoEndpoint = true,
            SaveTokens = true
        };
        options.Scope.Clear();
        options.Scope.Add("openid");
        return options;
    }
    
    0 讨论(0)
  • 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<string,string> Get()
        {
            var userPrinciple = User as ClaimsPrincipal;
            var claims = new Dictionary<string, string>();
    
            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.

    0 讨论(0)
  • 2020-12-23 15:50

    If you want to use standard .Net Role mappings with Keycloak Client Roles, setup like so:

    Startup.cs:

        services.AddAuthorization(options =>
        {
            options.AddPolicy("Users", policy =>
            policy.RequireRole("Users"));
        });
    
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        })
        .AddCookie()
        .AddOpenIdConnect(options =>
        {
            options.Authority = Configuration["Authentication:oidc:Authority"]
            options.ClientId = Configuration["Authentication:oidc:ClientId"];
            options.ClientSecret = Configuration["Authentication:oidc:ClientSecret"];
            options.RequireHttpsMetadata = false;
            options.GetClaimsFromUserInfoEndpoint = true;
            options.SaveTokens = true;
            options.RemoteSignOutPath = "/SignOut";
            options.SignedOutRedirectUri = "Redirect-here";
            options.ResponseType = "code";
    
        });
    

    appsettings.json:

      "Authentication": {
        "oidc": {
          "Authority":"http://your-keycloak-server/auth/realms/your-realm",
          "ClientId":"Your-Client-Name",
          "ClientSecret":"Your-client-secret"
        }
      }
    

    Keycloak Client Settings:

    • Create new Token Mapper
    • Mapper-Values (enter your own client name)

    Now you can use standard authorize role statements to apply your Keycloak Client Roles to your ASP.NET project:

    [Authorize(Roles = "Users")]
    
    0 讨论(0)
提交回复
热议问题