.NET Core IdentityServer4實戰 第六章-Consent授權頁

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

在identityServer4中登陸頁面只要是成功了,就會註冊一個Cookie在伺服器資源上,像現在大部分的網站第三方授權,都是經過一個頁面,然後選需要的功能,IdentityServer4也給我們提供了,只要你登陸成功,就會跳轉到Consent/Index(Get)中,所以我們只要在其中做手腳就 ...


  在identityServer4中登陸頁面只要是成功了,就會註冊一個Cookie在伺服器資源上,像現在大部分的網站第三方授權,都是經過一個頁面,然後選需要的功能,IdentityServer4也給我們提供了,只要你登陸成功,就會跳轉到Consent/Index(Get)中,所以我們只要在其中做手腳就好了。

  在編寫代碼之前我們要知道IdentityServer的三個介面, IClientStore 是存放客戶端信息的, IResourceStore 是存放資源API信息的,這兩個介面都是在IdentityServer4的Stores的命名空間下,還有一個介面是 IIdentityServerInteractionService 用於與IdentityServer通信的服務,主要涉及用戶交互。它可以從依賴註入系統獲得,通常作為構造函數參數註入到IdentityServer的用戶界面的MVC控制器中。

  下麵我們創建一個Consent控制器在認證伺服器上,名為 ConsentController ,在其中我們需要將這三個介面通過構造函數構造進來。

public class ConsentController : Controller
    {
        private readonly IClientStore _clientStore;
        private readonly IResourceStore _resourceStore;
        private readonly IIdentityServerInteractionService _identityServerInteractionService;
        public ConsentController(
          IClientStore clientStore,
          IResourceStore resourceStore, 
          IIdentityServerInteractionService identityServerInteractionService)
        {
            _clientStore = clientStore;
            _resourceStore = resourceStore;
            _identityServerInteractionService = identityServerInteractionService;
        }
}

在控制器中,因為登陸成功是從Account控制器調過來的,那個時候還帶著ReturnUrl這個而參數,我們在這個控制器中也需要ReturnUrl,所以在Get方法中寫上該參數,要不然跳轉不過來的。

public async Task<IActionResult> Index(string returnUrl)
        {
            var model =await BuildConsentViewModel(returnUrl);return View(model);
        }

其中調用了 BuildConsentViewModel 方法用於返回一個consent對象,其中我們使用 _identityServerInteractionService 介面獲取了上下文,然後再通過其餘的兩個介面找到它客戶端還有資源api的信息。然後再調用了自定義的 CreateConsentViewModel 對象創建了consent對象。

/// <summary>
        /// 返回一個consent對象
        /// </summary>
        private async Task<ConsentVm> BuildConsentViewModel(string returlUrl)
        {
            //獲取驗證上下文
            var request = await _identityServerInteractionService.GetAuthorizationContextAsync(returlUrl);
            if (request == null)
                return null;
            //根據上下文獲取client的信息以及資源Api的信息
            var client = await _clientStore.FindEnabledClientByIdAsync(request.ClientId);
            var resources = await _resourceStore.FindEnabledResourcesByScopeAsync(request.ScopesRequested);
            //創建consent對象
            var vm =  CreateConsentViewModel(request,client,resources);
            vm.ReturnUrl = returlUrl;
            return vm;
        }

 在其中創建對象並返回,只不過在獲取ResourceScopes的時候,它是一個ApiResource,所以需要先轉換成Scopes然呢再Select一下變成我們的ViewModel.

/// <summary>
        /// 創建consent對象
        /// </summary>
        private ConsentVm CreateConsentViewModel(AuthorizationRequest request,Client client,Resources resources)
        {
            var vm = new ConsentVm(); 
            vm.ClientId = client.ClientId;
            vm.Logo = client.LogoUri;
            vm.ClientName = client.ClientName;
            vm.ClientUrl = client.ClientUri;//客戶端url
            vm.RemeberConsent = client.AllowRememberConsent;//是否記住信息
            vm.IdentityScopes = resources.IdentityResources.Select(i=>CreateScopeViewModel(i));
            vm.ResourceScopes = resources.ApiResources.SelectMany(u => u.Scopes).Select(x => CreatesScoreViewModel(x));
            return vm;
        }
        public ScopeVm CreatesScoreViewModel(Scope scope)
        {
            return new ScopeVm
            {
                name = scope.Name,
                DisplayName = scope.DisplayName,
                Description = scope.Description,
                Required = scope.Required,
                Checked = scope.Required,
                Emphasize = scope.Emphasize
            };
        }
        private ScopeVm CreateScopeViewModel(IdentityResource identityResource)
        {
            return new ScopeVm
            {
                name = identityResource.Name,
                DisplayName = identityResource.DisplayName,
                Description = identityResource.Description,
                Required = identityResource.Required,
                Checked = identityResource.Required,
                Emphasize = identityResource.Emphasize
            };
        }

以上我們的控制器就完成了,現在我們搞一下視圖,在視圖中我們就是簡單做一下,使用ConsentVm作為視圖綁定對象,在之中我遇到了一個Bug,我用 @Html.Partial("_ScopeListItem", item); 的時候突然就報錯了,在頁面上顯示一個Task一大堆的錯誤信息,我也不知道啥情況(望大佬解決),換成不是非同步的就行了。

<p>Consent Page</p>
@using mvcWebFirstSolucation.Models;
@model ConsentVm
<div class="row page-header">
    <div class="col-sm-10">
        @if (!string.IsNullOrWhiteSpace(Model.Logo))
        {
            <div>
                <img src="@Model.Logo" /> 
            </div>
        }
        <h1>
            @Model.ClientName
            <small>歡迎來到第三方授權</small>
        </h1>

    </div>
</div>
<div class="row">
    <div class="col-sm-8">
        <form asp-action="Index">
            <input type="hidden" asp-for="ReturnUrl" />
            <div class="panel">
                <div class="panel-heading">
                    <span class="glyphicon glyphicon-tasks"></span>
                    用戶信息
                </div>
                <ul class="list-group">
                    @foreach (var item in Model.IdentityScopes)
                    {
                        @Html.Partial("_ScopeListItem", item);
                    }
                </ul>
            </div>
            <div class="panel">
                    <div class="panel-heading">
                        <span class="glyphicon glyphicon-tasks"></span>
                        應用許可權
                    </div>
                    <ul class="list-group">
                        @foreach (var item in Model.ResourceScopes)
                        {
                            @Html.Partial("_ScopeListItem", item);
                        }
                    </ul>
                </div>

            <div>
                <label>
                    <input type="checkbox" asp-for="RemeberConsent" />
                    <strong>記住我的選擇</strong>
                </label>
            </div>
            <div>
                <button value="yes" class="btn btn-primary" name="button"  autofocus>同意</button>
                <button value="no" name="button">取消</button>
                @if (!string.IsNullOrEmpty(Model.ClientUrl))
                {
                    <a href="@Model.ClientUrl" class="pull-right btn btn-default">
                        <span class="glyphicon glyphicon-info-sign"></span>
                        <strong>@Model.ClientUrl</strong>
                    </a>
                }
            </div>
        </form>
    </div>
</div>

下麵是局部視圖的定義,傳過來的對象是 ResourceScopes 和 IdentityScopes ,但他們都是對應ScopeVm,在其中呢就是把他們哪些許可權列出來,然後勾選,在它的父頁面已經做了post提交,所以我們還得弄個控制器。

@using mvcWebFirstSolucation.Models;
@model ScopeVm

<li>
    <label>
        <input type="checkbox" 
               name="ScopesConsented"
               id="[email protected]" 
               value="@Model.name" 
               checked="@Model.Checked"
               disabled="@Model.Required"/>

        @if (Model.Required)
        {   
            <input type="hidden" name="ScopesConsented" value="@Model.name" />
        }

        <strong>@Model.name</strong>
        @if (Model.Emphasize)
        {
            <span class="glyphicon glyphicon-exclamation-sign"></span>
        }
    </label>
    @if (!string.IsNullOrEmpty(Model.Description))
    {
        <div>
            <label for="[email protected]">@Model.Description</label>
        </div>
    }
</li>

 這個方法的參數是我們所自定義的實體,其中有按鈕還有返回的地址,在其中我們判斷了是否選擇OK,選擇不那就直接賦一個拒絕的指令,如果ok那麼就直接判斷是否有這個權力,因為我們在config中進行了配置,然後如果有,呢麽就直接添加,在不==null的清空下,我們根據 returlUrl 這個字元串獲取了請求信息,然後通過 GrantConsentAsync 方法直接同意了授權,然後直接跳轉過去,就成功了。

        [HttpPost]
        public async Task<IActionResult> Index(InputConsentViewModel viewmodel)
        {
            // viewmodel.ReturlUrl
            ConsentResponse consentResponse = null;
            if (viewmodel.Button =="no")
            {
                consentResponse = ConsentResponse.Denied;
            }
            else
            {
                if (viewmodel.ScopesConsented !=null && viewmodel.ScopesConsented.Any()) 
                {
                    consentResponse = new ConsentResponse
                    {
                        RememberConsent = viewmodel.RemeberConsent,
                        ScopesConsented = viewmodel.ScopesConsented
                    };
                }
            }
            if (consentResponse != null)
            {
                var request = await _identityServerInteractionService.GetAuthorizationContextAsync(viewmodel.ReturnUrl);
                await _identityServerInteractionService.GrantConsentAsync(request, consentResponse);
                return Redirect(viewmodel.ReturnUrl);
            }
            return View(await BuildConsentViewModel(viewmodel.ReturnUrl));
        }

最後,在調試的時候一定要Client的 RequireConsent 設置為true.

 

 


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

-Advertisement-
Play Games
更多相關文章
  • 捕捉信號 Go // 運行此程式,控制台將列印"Waiting for signal" // 按Ctrl + C 發送信號以關閉程式,將發生中斷 // 隨後控制台依次列印"Signal .."、"Exiting..." package main import ( "os" "os/signal" " ...
  • 客戶端與服務端多功能傳輸小程式 server.py ...
  • 擁抱開源的腳步,我們從來都是一直在路上;.NETCore作為後起之秀,帶給我們太多的驚喜和感動;但是也正是由於年輕,.NETCore 的生態還是不夠完善,這就非常需要我們社區的力量,需要大家一起參與,把開源社區好的工具、組件、應用接入到 .NETCore 應用中。 ...
  • 系列目錄 1. "第一章|理論基礎+實戰控制台程式實現AutoFac註入" 1. 第二章|AutoFac的常見使用套路 1. 第三章|實戰Asp.Net Framework Web程式實現AutoFac註入 1. 第四章|實戰Asp.Net Core自帶DI實現依賴註入 1. 第五章|實戰Asp.N ...
  • 非同步轉同步-PushFrame 本文通過PushFrame,實現非同步轉同步 首先有一個非同步方法,如下非同步任務延時2秒後,返回一個結果 在UI線程執行此任務,嘗試轉化為同步 PushFrame非同步轉同步的實現: 測試結果: Task不帶返回值的處理: PushFrame的缺陷 PS:pushFrame ...
  • 前言: 平時在實際工作中很少用到這個,雖然都是一些比較基礎的東西,但一旦遇到了,又不知所云。剛好最近接觸了一些相關這方面的項目,所以也算是對 這些內容重新溫習實踐了一遍。所以這篇不僅作為個人備忘,也分享給各位重溫一遍。 要學會位運算,首先要清楚什麼是位運算?程式中的所有內容在電腦記憶體中都是以二進位 ...
  • 在業務型的系統開發中,我們需要維護各種個樣的類型,比如客戶類型、客戶行業、商品類型等等,這些類型往往信息量不多,並且相似度極高,如果採用一類型一表去設計,將會造成極大的工作量,通過將這部分類型的信息進行抽象,利用欄位去存儲類型區分,共用表結構,來達到相容各種類型的功能,也就是設計一個數據字典,而對於 ...
  • 窗體設計: 代碼: private void button_src_Click(object sender, EventArgs e) { OpenFileDialog openFile = new OpenFileDialog(); openFile.Title = "請選擇待校正影像"; ope ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...