IdentityServer4-MVC+Hybrid實現Claims受權驗證(四)

       上節以對話形式,大概說了幾種客戶端受權模式的原理,這節重點介紹Hybrid模式在MVC下的使用。且爲實現IdentityServer4從數據庫獲取User進行驗證,並對Claim進行權限設置打下基礎(第五節介紹)。html

       本節內容比較多,且涉及1、二節的內容,若有不懂,可先熟悉1、二節知識。git


1、新建受權服務,命名爲AuthServer

      (1)新建Web API項目,不用配置HTTPS,不進行身份驗證。github

       設置成控制檯方式運行,端口設爲5000。數據庫

       安裝IdentityServer4api

       在Config.cs類中,添加以下代碼:服務器

public class Config
    {

        public static List<TestUser> GetUsers()
        {
            return new List<TestUser>
            {
                new TestUser
                {
                    SubjectId = "1",
                    Username = "test",
                    Password = "123",

                    Claims = new List<Claim>
                    {
                        new Claim("role", "user")
                    }
                },
                new TestUser
                {
                    SubjectId = "2",
                    Username = "admin",
                    Password = "123",

                    Claims = new List<Claim>
                    {
                        new Claim("role", "admin")
                    }
                }
            };
        }

        public static IEnumerable<IdentityResource> GetIdentityResources()
        {
            return new List<IdentityResource>
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
                //new IdentityResource("roles","role",new List<string>{ "role"})
            };
        }

        public static IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>
            {
                new ApiResource("api1", "My API")
                //new ApiResource("api1", "My API",new List<string>(){ "role"})
            };
        }

        // clients want to access resources (aka scopes)
        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>
            {
                new Client
                {
                    ClientId = "AuthServer",
                    AllowedGrantTypes = GrantTypes.ClientCredentials,
                    ClientSecrets =
                    {
                        new Secret("secret".Sha256())
                    },
                    AllowedScopes = { "api1" },
                    Claims= new List<Claim>(){new Claim("role","AuthServer") },
                    ClientClaimsPrefix = ""
                },
                // OpenID Connect implicit flow client (MVC)
                new Client
                {
                   ClientId = "mvc",
                   ClientName = "MVC Client",
                   AllowedGrantTypes = GrantTypes.Hybrid,
                   ClientSecrets =
                   {
                       new Secret("secret".Sha256())
                   },
                   // where to redirect to after login
                   RedirectUris = { "http://localhost:5002/signin-oidc" },

                   // where to redirect to after logout
                   PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },

                  AllowedScopes = new List<string>
                  {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
                    //"roles"
                  }
                }
            };
        }
}

       這裏IdentityResource映射於那些關於用戶信息的scope, ApiResource映射於API資源的scopes。cookie

 

      (2)打開Startup.cs,在ConfigureServices裏面調用AddIdentityServer來把Identity Server註冊到ASP.NET Core的容器裏面;隨後我調用了AddDeveloperSigningCredentials方法,它會建立一個用於對token簽名的臨時密鑰材料(可是在生產環境中應該使用可持久的密鑰材料)mvc

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();

            services.AddIdentityServer()
               .AddDeveloperSigningCredential()
               .AddTestUsers(Config.GetUsers())
               .AddInMemoryIdentityResources(Config.GetIdentityResources())
               .AddInMemoryApiResources(Config.GetApiResources())
               .AddInMemoryClients(Config.GetClients());
        }

      (3)打開Configure方法,把IdentityServer添加到ASP.NET Core的管道里。app

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseIdentityServer();
            //MVC配置
            app.UseStaticFiles();
            app.UseMvcWithDefaultRoute();
        }

      (4)而後下載登陸用的UI: https://github.com/IdentityServer/IdentityServer4.Quickstart.UIasync

       把圖中三個文件複製到AuthServer項目目錄下。

       

       複製完後項目以下:


 

2、新建MVC客戶端,命名爲MvcClient

      (1)設置端口爲5002。

       修改Start.cs的ConfigureServices方法爲:

public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            services.AddMvc();

            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

            services.AddAuthentication(options =>
            {
                options.DefaultScheme = "Cookies";
                options.DefaultChallengeScheme = "oidc";
            })
            .AddCookie("Cookies", options => 
            {
                //無權限,顯示的頁面
                options.AccessDeniedPath = "/Authorization/AccessDenied";
            })
            .AddOpenIdConnect("oidc", options =>
            {
                options.SignInScheme = "Cookies";

                options.Authority = "http://localhost:5000";
                options.RequireHttpsMetadata = false;

                options.ClientId = "mvc";
                options.ResponseType = "code id_token";
                options.Scope.Clear();
                options.Scope.Add("openid");
                options.Scope.Add("profile");
                //options.Scope.Add("roles");

                options.SaveTokens = true;
                options.ClientSecret = "secret";
                options.GetClaimsFromUserInfoEndpoint = true;

                //options.ClaimActions.MapUniqueJsonKey("role", "role");


                //options.TokenValidationParameters = new TokenValidationParameters
                //{
                //    NameClaimType = JwtClaimTypes.GivenName,
                //    RoleClaimType = JwtClaimTypes.Role
                //};
            });
       }

       AddAuthentication方法來添加和配置身份認證中間件。這裏使用Cookie做爲驗證用戶的首選方式,而DefaultScheme = "Cookies",這個"Cookies"字符串是能夠任意填寫的,只要與後邊的一致便可。可是若是同一個服務器上有不少應用的話,這個Scheme的名字不能重複。

       DefaultChanllangeScheme設爲"oidc", 這個名字與後邊配置OpenIdConnect的名字要同樣. 當用戶須要登錄的時候, 將使用的是OpenId Connect Scheme。

       AddCookie其參數是以前配置的DefaultScheme名稱,這配置了Cookie的處理者,並讓應用程序爲咱們的DefaultScheme啓用了基於Cookie的身份認證。一旦ID Token驗證成功而且轉化爲Claims身份標識後,這些信息就將會保存於被加密的Cookie裏。

       AddOpenIdConnect方法添加了對OpenID Connect流程的支持,它讓配置了用來執行OpenId Connect 協議的處理者。這個處理者會負責建立身份認證請求,Token請求和其它請求,並負責ID Token的驗證工做。它的身份認證scheme就是以前配置的"oidc",它的意思就是若是該客戶端的某部分要求身份認證的時候,OpenID Connect將會做爲默認方案被觸發(由於以前設置的DefaultChallengeScheme是"oidc", 和這裏的名字同樣)。

       SignInScheme和上面的DefaultScheme一致,它保證身份認證成功的結果將會被保存在方案名爲"Cookies"的Cookie裏。

       Authority就是Identity Provider的地址。

       ClientIdSecret要與IdentityProvider裏面的值同樣。

       請求的Scope有openid和profile,其實中間件默認也包括了這些scope,可是寫出來更明確一些。

       SaveTokens=true,表示容許存儲從Identity Provider那裏得到的tokens。

 

      (2)修改Configure方法爲:

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseAuthentication();

            app.UseStaticFiles();
            app.UseMvcWithDefaultRoute();
        }

      (3)而後對HomeController加上身份驗證。[Authorize]

       

      (4)再修改About的頁面,顯示User的Claim信息。

@{
    ViewData["Title"] = "About";
}
<h2>@ViewData["Title"]</h2>

@*<dt>Access Token</dt>
<dd>@ViewData["AccessToken"]</dd>*@

<dl>
    @foreach (var claim in User.Claims)
    {
        <dt>@claim.Type</dt>
        <dd>@claim.Value</dd>
    }
</dl>

 

      (5)如今,能夠運行AuthServer和MvcClient項目了。

       

      (6)輸入Config文件中的TestUser的用戶,密碼都設爲123,點擊Login

       

       容許受權

       查看About頁面,顯示了user相關的claim信息。

       

      (7)固然,登出功能還沒實現,這裏先實現登出。打開圖中cshtml文件

       

      添加以下代碼:

 @if (User.Identity.IsAuthenticated)
 {
     <li><a asp-area="" asp-controller="Home" asp-action="Logout">Logout</a></li>
 }

       

       而後在HomeController控制器中添加Logout方法

         public async Task Logout()

            {

                await HttpContext.SignOutAsync("Cookies");

                await HttpContext.SignOutAsync("oidc");

            }

       首先要清除本地的Cookie,這個Cookie的名字要與以前配置的默認方案裏的名字一致,這一步就至關於登出MVC客戶端。

       後一行代碼的做用是跳轉回到Identity Provider,而後用戶能夠繼續登出IDP, 也就是IDP會清除它的Cookie。

      (8)接着在AuthServer中的Quickstart/Account/AccountOptions實現自動跳轉回登陸頁面。

       

       好了,登陸登出實現完了,咱們接着實現Claim權限限制。


 

3、爲MVC客戶端設置Claim身份驗證

       (1)添加TestUser的Claim中Type爲role

       

      (2)定義用戶信息scope的role信息

        

       第一個參數是scope的名字,第二個參數是scope的顯示名,第三個參數是它所包含的claim類型,這裏就是「role」。

      (3)而後還須要客戶端容許請求「roles」這個scope

       

 

      (4)MVC客戶端的配置,打開MVC的startup,添加「roles」這個scope:options.Scope.Add("roles");

        把role claim 映射到User.Claims裏:options.ClaimActions.MapUniqueJsonKey("role", "role");

        role claim映射成ASP.NET Core MVC能夠識別的角色Roles。

options.TokenValidationParameters = new TokenValidationParameters
{
    NameClaimType = JwtClaimTypes.GivenName,
    RoleClaimType = JwtClaimTypes.Role
};

       這樣MVC中的role就能夠識別User.Claims的role了。

       

      (6)最後在MvcClient項目HomeController中   About前,加上role爲admin身份驗證。[Authorize(Roles ="admin")]

       

       而後運行,先用test帳號登陸進行驗證。

       發現點About頁面沒有權限進不去

       

       而後登出,換admin帳號登陸

       

       User.Claims的role成功被MVC中角色role識別,展現About頁面。

       


 

       這節主要介紹Hybrid在MVC下的使用,包括User的登陸登出和Claim對MVC的身份受權。

       然而,這只是針對內存用戶TestUser進行操做的,顯示實際項目中不能知足咱們需求。下節將在本節的基礎上介紹如何實現IdentityServer4從數據庫獲取User進行驗證並對Claim進行身份驗證。

       參考博客: http://www.javashuo.com/article/p-dwismktz-w.html

       源碼地址:https://github.com/Bingjian-Zhu/Mvc-HybridFlowV0.git

相關文章
相關標籤/搜索