.NET Core IdentityServer4實戰 第Ⅴ章-單點登錄

来源:https://www.cnblogs.com/ZaraNet/archive/2019/07/05/11136468.html
-Advertisement-
Play Games

OiDc可以說是OAuth的改造版,在最初的OAuth中,我們需要先請求一下認證伺服器獲取下Access_token,然後根據Access_token去Get資源伺服器, 況且OAuth1 和 2 完全不相容,易用性差,而OIDC可以在登陸的時候就把信息返回給你,不需要你在請求一下資源伺服器。下麵我 ...


  OiDc可以說是OAuth的改造版,在最初的OAuth中,我們需要先請求一下認證伺服器獲取下Access_token,然後根據Access_token去Get資源伺服器, 況且OAuth1 和 2 完全不相容,易用性差,而OIDC可以在登陸的時候就把信息返回給你,不需要你在請求一下資源伺服器。下麵我們根據Oidc來做一個單點登錄。

  新建三個項目(.NET Core Mvc)兩個Client(埠5001,5002),一個Server(5000),首先在Server中添加IdentityServer4的引用。

  在Server中Config.cs用於模擬配置。

    public class Config
    {
        public static IEnumerable<ApiResource> GetApiResource()
        {
            return new List<ApiResource>
            {
                new ApiResource("api","My Api App")
            };
        }
        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>
            {
                new Client()
                {
                    ClientId = "mvc",
                    AllowedGrantTypes = GrantTypes.Implicit,
                    ClientSecrets ={
                        new Secret("secret".Sha256())
                    },
                    RequireConsent = false,
                    RedirectUris = {"http://localhost:5001/signin-oidc",
                        "http://localhost:5002/signin-oidc" } ,
                    PostLogoutRedirectUris = {"http://localhost:5001/signout-callback-oidc" ,
                        "http://localhost:5002/signout-callback-oidc" },
                    AllowedScopes = {
                        IdentityServerConstants.StandardScopes.Profile,
                        IdentityServerConstants.StandardScopes.OpenId
                    }
                }
            };
        }
        public static List<TestUser> GetTestUsers()
        {
            return new List<TestUser>
            {
                new TestUser()
                {
                    SubjectId = "10000",
                    Username = "zara",
                    Password = "112233"
                }
            };
        }
        public static IEnumerable<IdentityResource> GetIdentityResources()
        {
            return new List<IdentityResource>
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
                new IdentityResources.Email()
            };
        }
    }

GetClient方法中欄位為RedirectUris是登陸成功返回的地址,並且我們採用隱式模式(因為只是傳統web中傳遞Access_Token),RequireConsent是否出現同意授權頁面,這個我們後續再細說.寫完Config.cs後,我們需要依賴註入到IdentityServer中。

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;
            });
        //config to identityServer Services services.AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryClients(Config.GetClients()) .AddTestUsers(Config.GetTestUsers()) .AddInMemoryIdentityResources(Config.GetIdentityResources()) .AddInMemoryApiResources(Config.GetApiResource()); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }

 在Configure中添加代碼 app.UseIdentityServer(); .我們還需要添加一個登陸頁面,名為Account.cshtml.

@{
    ViewData["Title"] = "Index";
}

<h2>Index</h2>

@using mvcWebFirstSolucation.Models;
@model LoginVM;

<div class="row">
    <div class="col-md-4">
        <section>
            <form method="post" asp-controller="Account" asp-action="Login" asp-route-returnUrl="@ViewData["returnUrl"]">
                <h4>Use a local to log in .</h4>
                <hr />
                <div class="from-group">
                    <label asp-for="UserName"></label>
                    <input asp-for="UserName" class="form-control">
                    <span asp-validation-for="UserName" class="text-danger"></span>
                </div>
                <div class="from-group">
                    <label asp-for="PassWord"></label>
                    <input asp-for="PassWord" type="password" class="form-control">
                    <span asp-validation-for="UserName" class="text-danger"></span>
                </div>
                <div class="from-group">
                    <button type="submit" class="btn btn-default">log in </button>
                </div>
            </form>
        </section>
    </div>
</div>
@section Scripts
{
    @await Html.PartialAsync("_ValidationScriptsPartial")
}

在控制器中我們寫一個構造函數,用於將IdentityServer.Text給我們封裝好的對象傳過來,這個對象是我們在Config.cs中添加的用戶信息,也就是GetClients的返回值,全都在 TestUserStore 中。其中還有一個提供好的方法,來給我們用,如果驗證通過我們直接跳轉到了傳遞過來的ReturnUrl.

    public class AccountController : Controller
    {
        private readonly TestUserStore _users;
        public AccountController(TestUserStore ussotre)
        {
            _users = ussotre;
        }
        [HttpGet]
        [Route("/Account/Login")]
        public IActionResult Index(string ReturnUrl = null)
        
{
            ViewData["returnUrl"] = ReturnUrl;
            return View();
        }
        private IActionResult RediretToLocal(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            return RedirectToAction(nameof(HomeController.Index),"Home");
        }
        [HttpPost]
        public async Task<IActionResult> Login(LoginVM vm,string returnUrl = null)
        {
            if (ModelState.IsValid)
            {
                ViewData["returnUrl"] = returnUrl;
                var user =  _users.FindByUsername(vm.UserName);
                if (user==null)
                {
                    ModelState.AddModelError(nameof(LoginVM.UserName), "userName is exists");
                }
                else
                {
                    if(_users.ValidateCredentials(vm.UserName, vm.PassWord))
                    {
                        var props = new AuthenticationProperties
                        {
                            IsPersistent = true,
                            ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromMinutes(30))
                        };
                        await Microsoft.AspNetCore.Http
                            .AuthenticationManagerExtensions
                                .SignInAsync( HttpContext, user.SubjectId, user.Username, props );

                        return RediretToLocal(returnUrl);
                    }

                    ModelState.AddModelError(nameof(LoginVM.PassWord), "Wrong Password");
                }
            }
            return View();
        }
    }

這個時候最基本的服務端已經配置成功了,我們開始配置受保護的客戶端吧。

在客戶端中我們不需要引入IdentityServer,因為我們只是去請求服務端然後看看cookies有沒有在而已,所以我們只需要給受保護的客戶端的Api做好安全判斷就好.

在受保護的控制器中添加 [Authorize] 標識。然後再Startup.cs中添加安全驗證。並且在Configure中use下 app.UseAuthentication(); 

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:5000";
                options.RequireHttpsMetadata = false;
                options.ClientId = "mvc";
                options.ClientSecret = "secret";
                options.SaveTokens = true;
            });

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

在首頁中最好遍歷下Claims對象,這個是通過OIDC直接給我們返回回來的.(最後另一個客戶端也這麼乾!)

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

現在我們啟動項目看一下效果吧。

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 記錄一下使用SMTP協議發送郵件 註: 1、授權碼需要去郵箱客戶端里的POP3 /SMTP選項里開通即可獲取授權碼,不需要使用郵箱密碼。使用授權碼即可通過第三方程式調用其郵箱代為發送郵件。開通方法登陸郵箱即可看到,就不再說明(真不清楚也可自行百度一下)。 2、如需使用qq郵箱作為發送端,需要修改郵箱 ...
  • 使用System.Collections.ArrayList.Sort()對象數組自定義排序 其核心為比較器的實現,比較器為一個類,繼承了IComparer介面並實現int IComparer.Compare(Object x, Object y)方法,該方法實現自定義排序的比較方式,可以通過使用不 ...
  • 題目描述 輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重覆的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。 解題思路 基礎知識 前序遍歷:根結點 > 左子樹 > ...
  • Start():開始或繼續計時Stop():停止計時ReSet():清空計時ReStart():清空計時並開始計時 ...
  • Kibana從6.6.0版本開始支持中文 參考: "https://github.com/anbai inc/Kibana_Hanization" 漢化方法如下: 以現行最新版本7.2.0為例,測試機器為Windows 10 打開 找到 ,如果沒找到自行添加如下文本 啟動Kibana,應該就可以查看 ...
  • 在IT圈混跡了近十年,今已正當而立之年卻仍一事無成,心中倍感惶恐慚愧。面對竟爭如此激列的環境,該如何應對?卻也知不能讓自已閑著,得轉起來,動起來。於是,便想著利用最新技術棧將自已原來的收費產品重寫一次,且完全開放免費的提供給最終用戶使用。這也算是讓自已多年的行業積累能有一個更大的擴展,同時也能讓有網... ...
  • C# 7.0的語法主要是優化了之前的寫法,使得更加簡潔方便。try catch when 這個使用場景很少,正常的開發無業務處理的時候不建議使用 。 #region 2.字元串嵌入值 Console.WriteLine("lxx__lxx____字元串嵌入值lxx__lxx____"); Conso ...
  • F1-F12 視窗快捷鍵 代碼快捷鍵 編輯快捷鍵 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...