1. 程式人生 > 實用技巧 ><六>OIDC 客戶端的引用服務端登入頁面的實現

<六>OIDC 客戶端的引用服務端登入頁面的實現

上一節服務端已經弄好了,那麼我們來建立一個mvc客戶端,訪問客戶端的時候直接呼叫服務端的登入頁面實現登入。

1、建立一個mvcclient, 埠預設為5004。

startup類中的 ConfigureServices函式總中加入認證配置

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(options =>
            {
                options.DefaultScheme = "Cookies
"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies") .AddOpenIdConnect("oidc", options => { options.SignInScheme = "Cookies"; options.Authority = "http://localhost:5003";//identity伺服器域名 options.RequireHttpsMetadata
= false; //沒有證書啥的不需要傳 options.ClientId = "myself"; //MVC服務端配置的clientId options.ClientSecret = "secret"; options.SaveTokens = true; }); services.AddControllersWithViews(); }

config中加入

   app.UseAuthentication();
   app.UseAuthorization();

預設的Homecontroller上面加上認證特性[Authorize]

這樣客戶端的配置就可以了。

2、修改一下服務端的程式碼

2.1、修改login前端,新增接收回調連結的引數

@{

    ViewData["Title"] = "登入";

}



<h2 style="text-align:center">登入管理系統</h2>



<hr />

<div>

    <form asp-controller="Account" asp-action="Login" method="post">

        <div>

            <label class="control-label">使用者名稱</label>

            <input class="form-control" type="text" name="username" />

        </div>

        <div>

            <label class="control-label">密碼</label>

            <input class="form-control" type="password" name="password" />

        </div>

        <div class="form-group">

            <input type="submit" value="登入" class="btn btn-primary" />

        </div>
        <input type="text" class="form-control" id="returnUrl" name="returnUrl" value="@ViewData["Rurl"]" />
    </form>

</div>

2.2、修改controller中的登入邏輯

 public class AccountController : Controller
    {
        private readonly TestUserStore _testUserStore;
     
        public AccountController( TestUserStore testUserStore)
        {
            _testUserStore = testUserStore;
        
        }
        public IActionResult Index()
        {
            return View();
        }

        public IActionResult Login(string returnUrl = "/Home/Index")
        {
            ViewData["Rurl"] = returnUrl;
            return View();
        }

        /// <summary>
        /// post 登入請求
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> Login(string userName, string password,string returnUrl)
        {
            if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
            {
                return Json(new { result = false, msg = "使用者名稱或者密碼不能為空!" });
            }
            var user = _testUserStore.FindByUsername(userName);
            if (user == null)
            {
                return Json(new { result = false, msg = "使用者不存在!" });
            }
            if (_testUserStore.ValidateCredentials(userName, password))
            {
                var props = new AuthenticationProperties
                {
                    IsPersistent = true,
                    ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromMinutes(3))
                };

                await AuthenticationManagerExtensions.SignInAsync(
                    HttpContext,
                    new IdentityServerUser(user.SubjectId),
                    props
                    );
                return Redirect(returnUrl);
            }
            return Json(new { result = false, msg = "使用者名稱密碼錯誤!" });
        }

    
    }

2.3、修改identity 中的配置 config.cs

 public static class Config
    {
        public static IEnumerable<ApiScope> GetScopes()
        {
            return new ApiScope[]
              {
                new ApiScope("api1scope"),
                new ApiScope("api2scope"),
                  //new ApiScope("scope2"),
              };
        }
        // 這個 Authorization Server 保護了哪些 API (資源)
        public static IEnumerable<ApiResource> GetApiResources()
        {
            return new[]
            {
                    new ApiResource("api", "My API")
                    {
                        Scopes = { "api1scope", "api2scope" }
                    }

                };
        }

        public static IEnumerable<IdentityResource> GetIdentityResources()
        {
            return new List<IdentityResource>
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
                new IdentityResources.Email(),
             };
        }

        // 哪些客戶端 Client(應用) 可以使用這個 Authorization Server
        public static IEnumerable<Client> GetClients()
        {
            return new[]
            {
                    new Client
                    {
                        ClientId = "myself",//定義客戶端 Id
                        ClientSecrets = new [] { new Secret("secret".Sha256()) },//Client用來獲取token
                        AllowedGrantTypes = GrantTypes.Implicit,//隱式流程

                        RequireConsent=false,
                        RedirectUris={"http://localhost:5004/signin-oidc"},//這個在identity的地址中是固定的,登入成功回撥處理地址,處理回撥返回的資料
                        
                        PostLogoutRedirectUris = { "http://localhost:5004/signout-callback-oidc" },//退出的時候會返回到這個地址

                        AllowedScopes =  {
                            IdentityServerConstants.StandardScopes.Profile,
                             IdentityServerConstants.StandardScopes.OpenId,
                           }// 允許訪問的 API 資源
                    }
                };
        }



        //測試使用者
        public static IEnumerable<TestUser> GetUsers()
        {
            return new[]
            {
                    new TestUser
                    {
                        SubjectId = "1",
                        Username = "myname",
                        Password = "password"
                    }
            };
        }
    }

2.4、在服務端startup中引用配置

  public void ConfigureServices(IServiceCollection services)
        {
            services.AddIdentityServer().AddDeveloperSigningCredential()
                .AddInMemoryApiResources(Config.GetApiResources())
                .AddInMemoryApiScopes(Config.GetScopes())
                .AddInMemoryClients(Config.GetClients())
                .AddTestUsers(Config.GetUsers().ToList())
                .AddInMemoryIdentityResources(Config.GetIdentityResources());
            services.AddControllersWithViews();
        }
AddDeveloperSigningCredential()這個是開發的簽名憑據,只能在開發使用,部署時需要更換。。這裡一定要加上,不然會報Nosigningcredentialisconfigured 的錯誤。

3、執行服務端和客戶端,瀏覽器訪問localhost:5004 就會跳到登入頁面,如下圖所示,這裡我把returnurl給顯示出來了。

4、輸入使用者名稱和密碼,即使服務端config.cs裡面TestUser配置的使用者名稱和密碼登入後就自動跳轉到client 埠5004的主頁面

如果客戶端沒有加上 app.UseAuthentication(); 的話會報signin-oidc 的頁面404的情況,也就說明了UseAuthentication會自動去解析cookie中的認證資料