基於IdentityServer4的單點登錄——IdentityServer


1.新建項目並添加引用

新建一個asp .net core 2.0的項目
引用IdentityServer4.AspNetIdentity

2.定義資源

新建Config.cs文件,定義Api資源與Identity資源
資源分為身份資源(Identity resources)和API資源(API resources)

(1)身份資源(Identity resources)

身份資源是用戶的用戶名,姓名或電子郵件地址等數據。身份資源具有唯一的名稱,可以為其分配任意聲明類型。然后,這些聲明將被包含在用戶的身份令牌中。客戶端將使用scope參數來請求訪問身份資源。
身份資源可以是IdentityServer自帶的資源,也可以是自定義的資源。

public static IEnumerable<IdentityResource> GetIdentityResources()
{
    //自定義身份資源
    var customProfile = new IdentityResource(
        name: "custom.profile",
        displayName: "Custom profile",
        claimTypes: new[] { "name", "email", "status" });
    return new List<IdentityResource>
    {
        //IdentityServer自帶的資源
        new IdentityResources.OpenId(),
        new IdentityResources.Profile(),
        customProfile
    };
}

(2)API資源(API resources)

API資源是客戶端訪問API獲得的資源

public static IEnumerable<ApiResource> GetApiResources()
{
    return new List<ApiResource>
    {
        //具有單一范圍的簡單API(在這種情況下,范圍名稱與api名稱相同)
        new ApiResource("api1", "My API"),
        // 擴展版本,更多的設置選項
        new ApiResource
        {
            Name = "api2",

            // 用於內部校驗的密碼
            // ApiSecrets是用於內部校驗的,API的名稱(Name)和密碼(ApiSecrets)可以用於認證
            ApiSecrets =
            {
                new Secret("secret".Sha256())
            },

            // 在訪問令牌中包含以下內容(除了subject ID)
            // UserClaims表示用戶聲明
            UserClaims = { JwtClaimTypes.Name, JwtClaimTypes.Email },

            // // 該API定義了兩個范圍
            Scopes =
            {
                new Scope()
                {
                    Name = "api2.full_access",
                    DisplayName = "Full access to API 2",
                },
                new Scope
                {
                    Name = "api2.read_only",
                    DisplayName = "Read only access to API 2"
                }
            }
        }
    };
}

3.定義客戶端Client

客戶端指想要訪問資源的Client

public static IEnumerable<Client> GetClients()
{
    return new List<Client>
    {
        //不一定要配置得這么復雜,根據需求來
        new Client
        {
            ClientId = "mvc",
            ClientName = "MVC Client",
            AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,

            RequireConsent = true,

            ClientSecrets = 
            {
                new Secret("secret".Sha256())
            },
            //這里配置客戶端的網址,多個客戶端則是多個網址
            RedirectUris = { "http://localhost:5002/signin-oidc" },
            PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
            //允許的范圍
            AllowedScopes =
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile,
                "api1"
            },
            AllowOfflineAccess = true
        }
    };
}

其他配置請參閱:
https://identityserver4.readthedocs.io/en/release/topics/clients.html

4.配置

把資源信息和客戶端信息交給IdentityServer

public void ConfigureServices(IServiceCollection services)
{
    //配置服務
    services.AddIdentityServer()
        //讀取客戶端列表
        .AddInMemoryClients(Clients.Get())
        //讀取身份資源列表
        .AddInMemoryIdentityResources(Resources.GetIdentityResources())
        //讀取API資源列表
        .AddInMemoryApiResources(Resources.GetApiResources())
        //設置臨時簽名憑據
        .AddDeveloperSigningCredential()
        //添加測試用戶
        .AddTestUsers(TestUsers.Users);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    //配置管道:注意配置管道要寫在路由的前面...
    app.UseIdentityServer();
}

這里需要注意的是,以上的資源信息和客戶端信息是存在內存中的,可以設置為讀取數據庫
參閱:https://identityserver4.readthedocs.io/en/release/quickstarts/8_entity_framework.html

5.多客戶端的統一登錄

(1)用戶表

//ApplicationUser繼承於IdentityUser,可以在此為用戶表添加屬性,字段
public class ApplicationUser : IdentityUser
{
}

(2)頁面

<div class="col-md-4">
    <section>
        <form asp-route-returnurl="@ViewData["ReturnUrl"]" method="post">
            <h4>Use a local account to log in.</h4>
            <hr />
            <div asp-validation-summary="All" class="text-danger"></div>
            <div class="form-group">
                <!--整個流程是根據郵箱進行注冊和登錄的-->
                <label asp-for="Email"></label>
                <input asp-for="Email" class="form-control" />
                <span asp-validation-for="Email" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Password"></label>
                <input asp-for="Password" class="form-control" />
                <span asp-validation-for="Password" class="text-danger"></span>
            </div>
            <div class="form-group">
                <div class="checkbox">
                    <label asp-for="RememberMe">
                        <input asp-for="RememberMe" />
                        @Html.DisplayNameFor(m => m.RememberMe)
                    </label>
                </div>
            </div>
            <div class="form-group">
                <button type="submit" class="btn btn-default">Log in</button>
            </div>
            <div class="form-group">
                <p>
                    <a asp-action="ForgotPassword">Forgot your password?</a>
                </p>
                <p>
                    <a asp-action="Register" asp-route-returnurl="@ViewData["ReturnUrl"]">Register as a new user?</a>
                </p>
            </div>
        </form>
    </section>
</div>

(3)登錄方法

這里是AspNet Identity的內容

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
    ViewData["ReturnUrl"] = returnUrl;
    if (ModelState.IsValid)
    {
        // 嘗試登錄
        // 需要注意的是,這里沒有對登錄失敗進行計數
        // 為了在登錄失敗多次之后觸發鎖定用戶,把lockoutOnFailure設置為true
        var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
        if (result.Succeeded)
        {
            _logger.LogInformation("User logged in.");
            return RedirectToLocal(returnUrl);
        }
        if (result.RequiresTwoFactor)
        {
            return RedirectToAction(nameof(LoginWith2fa), new { returnUrl, model.RememberMe });
        }
        if (result.IsLockedOut)
        {
            _logger.LogWarning("User account locked out.");
            return RedirectToAction(nameof(Lockout));
        }
        else
        {
            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            return View(model);
        }
    }
    return View(model);
}

6.設置IdentityServer項目的端口號為5000

7.其他

整個流程還需要包括注冊,注銷,忘記密碼,第三方登錄,修改用戶信息等,這些不屬於IdentityServer的討論范疇,在此不做討論


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM