aspnetcore 應用 接入Keycloak快速上手指南

登錄及身份認證是現代web應用最基本的功能之一,對於企業內部的系統,多個系統往往希望有一套SSO服務對企業用戶的登錄及身份認證進行統一的管理,提升用戶同時使用多個系統的體驗,Keycloak正是為此種場景而生。本文將簡明的介紹Keycloak的安裝、使用,並給出aspnetcore 應用如何快速接入Keycloak的示例。

Keycloak是什麼

Keycloak是一種面向現代應用和服務的開源IAM(身份識別與訪問管理)解決方案

Keycloak提供了單點登錄(SSO)功能,支持OpenID ConnectOAuth 2.0SAML 2.0標準協議,擁有簡單易用的管理控制台,並提供對LDAP、Active Directory以及Github、Google等社交賬號登錄的支持,做到了非常簡單的開箱即用。

官網: //www.keycloak.org/

Keycloak常用核心概念介紹

首先通過官方的一張圖來了解下整體的核心概念

image

這裡先只介紹4個最常用的核心概念:

  1. Users: 用戶,使用並需要登錄系統的對象

  2. Roles: 角色,用來對用戶的權限進行管理

  3. Clients: 客戶端,需要接入Keycloak並被Keycloak保護的應用和服務

  4. Realms: 領域,領域管理着一批用戶、證書、角色、組等,一個用戶只能屬於並且能登陸到一個域,域之間是互相獨立隔離的, 一個域只能管理它下面所屬的用戶

Keycloak服務安裝及配置

安裝Keycloak

Keycloak安裝有多種方式,這裡使用Docker進行快速安裝

登錄後複製

docker run -d --name keycloak \
    -p 8080:8080 \
    -e KEYCLOAK_USER=admin \
    -e KEYCLOAK_PASSWORD=admin \
    jboss/keycloak:13.0.0

訪問//localhost:8080並點擊Administration Console進行登錄

 

image

 

創建Realm

創建一個新的realm: demo,後續所有的客戶端、用戶、角色等都在此realm中創建

image

image

image

創建客戶端
創建前端應用客戶端

創建一個新的客戶端:KeycloakAuthaspnet,Access Type選擇public

image

關於客戶端的訪問類型(Access Type)

上面創建的2個客戶端的訪問類型分別是public、bearer-only,那麼為什麼分別選擇這種類型,實際不同的訪問類型有什麼區別呢?

事實上,Keycloak目前的訪問類型共有3種:

  • confidential:適用於服務端應用,且需要瀏覽器登錄以及需要通過密鑰獲取access token的場景。典型的使用場景就是服務端渲染的web系統。
  • public:適用於客戶端應用,且需要瀏覽器登錄的場景。典型的使用場景就是前端web系統,包括採用vue、react實現的前端項目等。
  • bearer-only:適用於服務端應用,不需要瀏覽器登錄,只允許使用bearer token請求的場景。典型的使用場景就是restful api。

 

Access Type 裏面選 Confidential,然後才有 Client Secret ,保存之後,會出現Credentials的Tab,記錄下這裡的secret,後面要用到

image

 

創建用戶和角色
創建角色

創建2個角色:admin、user

image

還可以創建全局的角色

image

 

創建用戶

創建1個用戶:geffzhang

image

 

綁定用戶和角色
給geffzhang 用戶分配角色admin和user

image

 

aspnetcore 應用集成Keycloak簡明指南

 

添加 Microsoft.AspNetCore.Authentication.OpenIdConnect  和  Microsoft.AspNetCore.Identity 包

 

<Project Sdk=”Microsoft.NET.Sdk.Web”>

  <PropertyGroup>
     <TargetFramework>net5.0</TargetFramework>
     <UserSecretsId>afab524d-850e-499a-bc13-98f61ca0eb3b</UserSecretsId>
     <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
   </PropertyGroup>

  <ItemGroup>
     <PackageReference Include=”Microsoft.AspNetCore.Authentication.OpenIdConnect” Version=”5.0.5″ />
     <PackageReference Include=”Microsoft.AspNetCore.Identity” Version=”2.2.0″ />
     <PackageReference Include=”Microsoft.VisualStudio.Azure.Containers.Tools.Targets” Version=”1.10.8″ />
     <PackageReference Include=”Microsoft.VisualStudio.Web.CodeGeneration.Design” Version=”5.0.2″ />
   </ItemGroup>

</Project>

 

Appsettings.json

 

image

 

image

 

// This method gets called by the runtime. Use this method to add services to the container.
     public void ConfigureServices(IServiceCollection services)
     {
         services.AddControllersWithViews();
        
         services.AddAuthentication(options =>
         {
             //Sets cookie authentication scheme
             options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
             options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
             options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
         })

        .AddCookie(cookie =>
         {
             //Sets the cookie name and maxage, so the cookie is invalidated.
             cookie.Cookie.Name = “keycloak.cookie”;
             cookie.Cookie.MaxAge = TimeSpan.FromMinutes(60);
             cookie.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
             cookie.SlidingExpiration = true;
         })
         .AddOpenIdConnect(options =>
         {
             /*
              * ASP.NET core uses the //*:5000 and //*:5001 ports for default communication with the OIDC middleware
              * The app requires load balancing services to work with :80 or :443
              * These needs to be added to the keycloak client, in order for the redirect to work.
              * If you however intend to use the app by itself then,
              * Change the ports in launchsettings.json, but beware to also change the options.CallbackPath and options.SignedOutCallbackPath!
              * Use LB services whenever possible, to reduce the config hazzle 🙂
             */

            //Use default signin scheme
             options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
             //Keycloak server
             options.Authority = Configuration.GetSection(“Keycloak”)[“ServerRealm”];
             //Keycloak client ID
             options.ClientId = Configuration.GetSection(“Keycloak”)[“ClientId”];
             //Keycloak client secret
             options.ClientSecret = Configuration.GetSection(“Keycloak”)[“ClientSecret”];
             //Keycloak .wellknown config origin to fetch config
             options.MetadataAddress = Configuration.GetSection(“Keycloak”)[“Metadata”];
             //Require keycloak to use SSL
             options.RequireHttpsMetadata = false;
             options.GetClaimsFromUserInfoEndpoint = true;
             options.Scope.Add(“openid”);
             options.Scope.Add(“profile”);
             //Save the token
             options.SaveTokens = true;
             //Token response type, will sometimes need to be changed to IdToken, depending on config.
             options.ResponseType = OpenIdConnectResponseType.Code;
             //SameSite is needed for Chrome/Firefox, as they will give http error 500 back, if not set to unspecified.
             options.NonceCookie.SameSite = SameSiteMode.Unspecified;
             options.CorrelationCookie.SameSite = SameSiteMode.Unspecified;
            
             options.TokenValidationParameters = new TokenValidationParameters
             {
                 NameClaimType = “name”,
                 RoleClaimType = ClaimTypes.Role,
                 ValidateIssuer = true
             };

         });

        /*
          * For roles, that are defined in the keycloak, you need to use ClaimTypes.Role
          * You also need to configure keycloak, to set the correct name on each token.
          * Keycloak Admin Console -> Client Scopes -> roles -> mappers -> create
          * Name: “role client mapper” or whatever you prefer
          * Mapper Type: “User Client Role”
          * Multivalued: True
          * Token Claim Name: role
          * Add to access token: True
          */

       
         /*
          * Policy based authentication
          */

        services.AddAuthorization(options =>
         {
             //Create policy with more than one claim
             options.AddPolicy(“users”, policy =>
             policy.RequireAssertion(context =>
             context.User.HasClaim(c =>
                     (c.Value == “user”) || (c.Value == “admin”))));
             //Create policy with only one claim
             options.AddPolicy(“admins”, policy =>
                 policy.RequireClaim(ClaimTypes.Role, “admin”));
             //Create a policy with a claim that doesn’t exist or you are unauthorized to
             options.AddPolicy(“noaccess”, policy =>
                 policy.RequireClaim(ClaimTypes.Role, “noaccess”));
         });

         /*
          * Non policy based authentication
          * Uncomment below and comment the policy section
          */
       
         //services.AddAuthorization();

    }

經過上述的配置,通過oidc 很容易就接入到了Keycloak。具體代碼請參見://github.com/NanoFabricFX/AspNetCore-keycloak/tree/dotnet5

 

運行效果,第一次訪問項目會跳轉Keycloak登錄頁

 

image

用戶登陸geffzhang

 

image

總結

Keycloak部署及接入簡單,輕量的同時功能又不失強大,非常適合企業內部的SSO方案。在Identity Server4 收費的背景之下,微軟計劃在.NET 6裏面繼續集成,已經被社區罵的狗血噴頭//devblogs.microsoft.com/aspnet/asp-net-core-6-and-authentication-servers/ 

 

相關文章: