4. 使用IdentityServer4 實現 基於OIDC 的內部MVC客戶端認證

1. 概述

  • 上一個實例 中實現了簡單的 ResourceOwnerPassword 授權.

  • 本例將使用IdentityServer4 實現內部系統的單點登錄,讓組織內部的MVC 客戶端使用認證中心的登錄頁實現登錄,使用的是OAuth2 的隱式授權碼模式Implicit AthorizationCode

  • MVC 客戶端集成IdentityServer4 認證時,爲簡單起見,將使用cookie存儲客戶端憑據;同時啓用IdentityServer4 內置的 OpenIdConnect(OIDC)身份認證服務。

2. 關鍵概念

  • IdentityResource : OIDC 協議中定義的身份認證資源,這種資源具有唯一名稱,資源聲明後將包含在用戶的身份令牌中。參考: https://docs.identityserver.io/en/3.1.0/topics/resources.html

  • IIdentityServerInteractionService : 這是IdentityServer4提供的認證交互接口。

3. 準備MVC Web客戶端

新建一個MVCClient 項目,設置訪問地址和端口爲:http://localhost:5030。

3.1 引用依賴包

 <PackageReference Include="IdentityServer4" Version="4.1.1" />

3.2 註冊OIDC 服務,並啓用認證中間件

// DI容器中註冊服務
services.AddAuthentication(opt =>
            {
                opt.DefaultScheme = "Cookies";
                opt.DefaultChallengeScheme = "oidc";
            }).AddCookie("Cookies")
            .AddOpenIdConnect("oidc", options =>
            {
                options.SignInScheme = "Cookies";
                options.Authority = "http://localhost:5010";
                options.RequireHttpsMetadata = false;

                options.ClientId = "mvc";
                options.SaveTokens = true;
            });

// ConfigureService 中啓用中間件
            app.UseAuthentication();

// 將受保護頁面使用【Authorize】 保護起來,訪問首頁時將重定向到Account/Login
 [Authorize]
    public class HomeController : Controller
{
……  ……
}

4. 服務端配置

4.1 添加IdentityResource(在server端的Config 類中添加) 和client

        public static List<IdentityResource> GetIdentityResources()
        {
            var result = new List<IdentityResource>
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile()
            };
            return result;
        }

// 新增一個client
           new Client
            {
                ClientId="mvc",
                ClientName="MVC Client",
                RequireConsent=false,
                AllowedGrantTypes= GrantTypes.Implicit, // 隱式授權碼
                RedirectUris={"http://localhost:5030/signin-oidc"}, // 這裏的回調地址是MVC客戶端的地址
                PostLogoutRedirectUris={"http://localhost:5030/signout-callback-oidc"},
                AllowedScopes= new List<string>
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile
                }

            }

// Startup 註冊IdentityResource

services.AddIdentityServer()
                .AddDeveloperSigningCredential()
                .AddInMemoryApiResources(Config.GetApiResources)
                .AddInMemoryIdentityResources(Config.GetIdentityResources())
                .AddInMemoryClients(Config.GetClients)
                .AddInMemoryApiScopes(Config.GetApiScopes) // 3.1 新增的坑,不加會報invalid_scope
                .AddTestUsers(Config.GetTestUsers())
                ;

5. 測試驗證

啓動服務端5010,和客戶端5030 此時客戶端將重定向到5010 的登錄頁Account/Login

可以輸入TestUsers中配置的用戶名密碼登錄

5.1 Account/Login 的登錄方法

       [HttpPost]
        public async Task<IActionResult> Login(LoginViewModel model, string returnUrl)
        {
            ViewData["ReturnUrl"] = returnUrl;
            var user = _users.FindByUsername(model.UserName);

            if (user == null)
            {
                ModelState.AddModelError(nameof(model.UserName), "User not exists.");
            }
            else
            {
                if (_users.ValidateCredentials(model.UserName, model.Password))
                {
                    var props = new AuthenticationProperties
                    {
                        IsPersistent = true,
                        ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromMinutes(30))
                    };
                    var u = new IdentityServerUser(user.SubjectId) { DisplayName = user.Username };

                    await Microsoft.AspNetCore.Http.AuthenticationManagerExtensions.SignInAsync(
                          this.HttpContext,
                          u,
                          props);
                    return Redirect(returnUrl);
                }
            }
            return View();

        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章