永久免费看黄A片无码软件,japanese 在线观看国产,强奷高H猛烈失禁潮喷播放,亚洲成精品自拍

rexian

咨詢電話:023-6276-4481

熱門文章

聯(lián)系方式

電 話:023-6276-4481

郵箱:broiling@qq.com

地址:重慶市南岸區(qū)亞太商谷6幢25-2

當(dāng)前位置:網(wǎng)站首頁 > 技術(shù)文章 > ASP.NET Identity高級(jí)技術(shù)

ASP.NET Identity高級(jí)技術(shù)

編輯:T.T 發(fā)表時(shí)間:2017-07-26 08:55:26
T.T

本章將完成對ASP.NET Identity的描述,向你展示它所提供的一些高級(jí)特性。我將演示,你可以擴(kuò)展ASP.NET Identity的數(shù)據(jù)庫架構(gòu),其辦法是在用戶類上定義一些自定義屬性。也會(huì)演示如何使用數(shù)據(jù)庫遷移,這樣可以運(yùn)用自定義屬性,而不必刪除ASP.NET Identity數(shù)據(jù)庫中的數(shù)據(jù)。還會(huì)解釋ASP.NET Identity如何支持聲明(Claims)概念,并演示如何將它們靈活地用來對動(dòng)作方法進(jìn)行授權(quán)訪問。最后向你展示ASP.NET Identity很容易通過第三方部件來認(rèn)證用戶,以此結(jié)束本章以及本書。將要演示的是使用Google賬號(hào)認(rèn)證,但ASP.NET Identity對于Microsoft、Facebook以及Twitter賬號(hào),都有內(nèi)建的支持。表15-1是本章概要。

表15-1. 本章概要
問題解決方案清單號(hào)
存儲(chǔ)用戶的附加信息定義自定義用戶屬性1–3, 8–11
更新數(shù)據(jù)庫架構(gòu)而不刪除用戶數(shù)據(jù)執(zhí)行數(shù)據(jù)庫遷移4–7
執(zhí)行細(xì)粒度授權(quán)使用聲明(Claims)12–14
添加用戶的聲明(Claims)使用ClaimsIdentity.AddClaims方法15–19
基于聲明(Claims)值授權(quán)訪問創(chuàng)建一個(gè)自定義的授權(quán)過濾器注解屬性20–21
通過第三方認(rèn)證安裝認(rèn)證提供器的NuGet包,將請求重定向到該提供器,并指定一個(gè)創(chuàng)建用戶賬號(hào)的回調(diào)URL。22–25

15.1 準(zhǔn)備示例項(xiàng)目

本章打算繼續(xù)使用第13章創(chuàng)建并在第14章增強(qiáng)的Users項(xiàng)目。對應(yīng)用程序無需做什么改變,但需要啟動(dòng)應(yīng)用程序,并確保數(shù)據(jù)庫中有一些用戶。圖15-1顯示了數(shù)據(jù)庫的狀態(tài),它含有上一章的用戶Admin、AliceBob以及Joe。為了檢查用戶,請啟動(dòng)應(yīng)用程序,請求/Admin/Index URL,并以Admin用戶進(jìn)行認(rèn)證。

圖15-1

圖15-1. Identity數(shù)據(jù)庫中的最初用戶

本章還需要一些角色。我用RoleAdmin控制器創(chuàng)建了角色UsersEmployees,并為這些角色指定了一些用戶,如表15-2所示。

表15-2. 角色及成員(作者將此表的標(biāo)題寫錯(cuò)了——譯者注)
角色成員
UsersAlice, Joe
EmployeesAliceBob

圖15-2顯示了由RoleAdmin控制器所顯示出來的必要的角色配置。

圖15-2

圖15-2. 配置本章所需的角色

15.2 添加自定義用戶屬性

我在第13章創(chuàng)建AppUser類來表示用戶時(shí)曾做過說明,基類定義了一組描述用戶的基本屬性,如E-mail地址、電話號(hào)碼等。大多數(shù)應(yīng)用程序還需要存儲(chǔ)用戶的更多信息,包括持久化應(yīng)用程序愛好以及地址等細(xì)節(jié)——簡言之,需要存儲(chǔ)對運(yùn)行應(yīng)用程序有用并且在各次會(huì)話之間應(yīng)當(dāng)保持的任何數(shù)據(jù)。在ASP.NET Membership中,這是通過用戶資料(User Profile)系統(tǒng)來處理的,但ASP.NET Identity采取了一種不同的辦法。

因?yàn)锳SP.NET Identity默認(rèn)是使用Entity Framework來存儲(chǔ)其數(shù)據(jù)的,定義附加的用戶信息只不過是給用戶類添加屬性的事情,然后讓Code First特性去創(chuàng)建需要存儲(chǔ)它們的數(shù)據(jù)庫架構(gòu)即可。表15-3描述了自定義用戶屬性的情形。

表15-3. 自定義用戶屬性的情形
問題回答
什么是自定義用戶屬性?自定義用戶屬性讓你能夠存儲(chǔ)附加的用戶信息,包括他們的愛好和設(shè)置。
為何要關(guān)心它?設(shè)置的持久化存儲(chǔ)意味著,用戶不必每次登錄到應(yīng)用程序時(shí)都提供同樣的信息。
在MVC框架中如何使用它?此特性不是由MVC框架直接使用的,但它在動(dòng)作方法中使用是有效的。

15.2.1 定義自定義屬性

清單15-1演示了如何給AppUser類添加一個(gè)簡單的屬性,用以表示用戶生活的城市。

清單15-1. 在AppUser.cs文件中添加屬性

using System;
using Microsoft.AspNet.Identity.EntityFramework;
namespace Users.Models {}

這里定義了一個(gè)枚舉,名稱為Cities,它定義了一些大城市的值,另外給AppUser類添加了一個(gè)名稱為City的屬性。為了讓用戶能夠查看和編輯City屬性,給Home控制器添加了幾個(gè)動(dòng)作方法,如清單15-2所示。

清單15-2. 在HomeController.cs文件中添加對自定義屬性的支持

using System.Web.Mvc;
using System.Collections.Generic;
using System.Web;
using System.Security.Principal;
namespace Users.Controllers {

    public class HomeController : Controller {

        [Authorize]
        public ActionResult Index() {
             return View(GetData("Index"));
        }

        [Authorize(Roles = "Users")]
        public ActionResult OtherAction() {
            return View("Index", GetData("OtherAction"));
        }

        private Dictionary<string, object> GetData(string actionName) {
            Dictionary<string, object> dict
                = new Dictionary<string, object>();
            dict.Add("Action", actionName);
            dict.Add("User", HttpContext.User.Identity.Name);
            dict.Add("Authenticated", HttpContext.User.Identity.IsAuthenticated);
            dict.Add("Auth Type", HttpContext.User.Identity.AuthenticationType);
            dict.Add("In Users Role", HttpContext.User.IsInRole("Users"));
            return dict;
        }

    }
}

我添加了一個(gè)CurrentUser屬性,它使用AppUserManager類接收了表示當(dāng)前用戶的AppUser實(shí)例。在GET版本的UserProps動(dòng)作方法中,傳遞了這個(gè)AppUser對象作為視圖模型。而在POST版的方法中用它更新了City屬性的值。清單15-3顯示了UserProps.cshtml視圖,它顯示了City屬性的值,并包含一個(gè)修改它的表單。

清單15-3. Views/Home文件夾中UserProps.cshtml文件的內(nèi)容

@using Users.Models
@model AppUser
@{ ViewBag.Title = "UserProps";}
<div class="panel panel-primary">
    <div class="panel-heading">
        Custom User Properties
    </div>
    <table class="table table-striped">
        <tr><th>City</th><td>@Model.City</td></tr>
    </table>
</div> 
@using (Html.BeginForm()) {
    <div class="form-group">
        <label>City</label>
        @Html.DropDownListFor(x => x.City, new SelectList(Enum.GetNames(typeof(Cities))))
    </div>
    <button class="btn btn-primary" type="submit">Save</button>
}

警告:創(chuàng)建了視圖之后不要啟動(dòng)應(yīng)用程序。在以下小節(jié)中,將演示如何保留數(shù)據(jù)庫的內(nèi)容,如果現(xiàn)在啟動(dòng)應(yīng)用程序,將會(huì)刪除ASP.NET Identity的用戶。

15.2.2 準(zhǔn)備數(shù)據(jù)庫遷移

Entity Framework Code First特性的默認(rèn)行為是,一旦修改了派生數(shù)據(jù)庫架構(gòu)的類,便會(huì)刪除數(shù)據(jù)庫中的數(shù)據(jù)表,并重新創(chuàng)建它們。在第14章可以看到這種情況,在我添加角色支持時(shí):當(dāng)重啟應(yīng)用程序后,數(shù)據(jù)庫被重置,用戶賬號(hào)也丟失。

不要啟動(dòng)應(yīng)用程序,但如果你這么做了,會(huì)看到類似的效果。在開發(fā)期間刪除數(shù)據(jù)沒什么問題,但如果在產(chǎn)品設(shè)置中這么做了,通常是災(zāi)難性的,因?yàn)樗鼤?huì)刪除所有真實(shí)的用戶賬號(hào),而備份恢復(fù)是很痛苦的事。在本小節(jié)中,我打算演示如何使用數(shù)據(jù)庫遷移特性,它能以比較溫和的方式更新Code First的架構(gòu),并保留架構(gòu)中的已有數(shù)據(jù)。

第一個(gè)步驟是在Visual Studio的“Package Manager Console(包管理器控制臺(tái))”中發(fā)布以下命令:

Enable-Migrations –EnableAutomaticMigrations

它啟用了數(shù)據(jù)庫的遷移支持,并在“Solution Explorer(解決方案資源管理器)”創(chuàng)建一個(gè)Migrations文件夾,其中含有一個(gè)Configuration.cs類文件,內(nèi)容如清單15-4所示。

清單15-4. Configuration.cs文件的內(nèi)容

namespace Users.Migrations {
using System;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;

    internal sealed class Configuration
            : DbMigrationsConfiguration<
    Users.Infrastructure.AppIdentityDbContext> {
        public Configuration() {
            AutomaticMigrationsEnabled = true;
            ContextKey = "Users.Infrastructure.AppIdentityDbContext";
        }

        protected override void Seed(Users.Infrastructure.AppIdentityDbContext context) {
            // This method will be called after migrating to the latest version.
            // 此方法將在遷移到最新版本時(shí)調(diào)用

            // You can use the DbSet<T>.AddOrUpdate() helper extension method
            // to avoid creating duplicate seed data. E.g.
            // 例如,你可以使用DbSet<T>.AddOrUpdate()輔助器方法來避免創(chuàng)建重復(fù)的種子數(shù)據(jù)
            //
            //    context.People.AddOrUpdate(
            //      p => p.FullName,
            //      new Person { FullName = "Andrew Peters" },
            //      new Person { FullName = "Brice Lambson" },
            //      new Person { FullName = "Rowan Miller" }
            //    );
            //
        }
    }
}

提示:你可能會(huì)覺得奇怪,為什么要在管理NuGet包的控制臺(tái)中輸入數(shù)據(jù)庫遷移的命令?答案是“Package Manager Console(包管理控制臺(tái))”是真正的PowerShell,這是Visual studio冒用的一個(gè)通用工具。你可以使用此控制臺(tái)發(fā)送大量的有用命令,詳見http://go.microsoft.com/fwlink/?LinkID=108518。

這個(gè)類將用于把數(shù)據(jù)庫中的現(xiàn)有內(nèi)容遷移到新的數(shù)據(jù)庫架構(gòu),Seed方法的調(diào)用為更新現(xiàn)有數(shù)據(jù)庫記錄提供了機(jī)會(huì)。在清單15-5中可以看到,我如何用Seed方法為新的City屬性設(shè)置默認(rèn)值,City是添加到AppUser類中自定義屬性。(為了體現(xiàn)我一貫的編碼風(fēng)格,我對這個(gè)類文件也進(jìn)行了更新。)

清單15-5. 在Configuration.cs文件中管理已有內(nèi)容

namespace Users.Migrations {

    internal sealed class Configuration
            : DbMigrationsConfiguration<AppIdentityDbContext> {

        public Configuration() {
            AutomaticMigrationsEnabled = true;
            ContextKey = "Users.Infrastructure.AppIdentityDbContext";
        }

        protected override void Seed(AppIdentityDbContext context) {

        }
    }
}

你可能會(huì)注意到,添加到Seed方法中的許多代碼取自于IdentityDbInit類,在第14章中我用這個(gè)類將管理用戶植入了數(shù)據(jù)庫。這是因?yàn)檫@個(gè)新添加的、用以支持?jǐn)?shù)據(jù)庫遷移的Configuration類,將代替IdentityDbInit類的種植功能,我很快便會(huì)更新這個(gè)類。除了要確保有admin用戶之外,在Seed方法中的重要語句是那些為AppUser類的City屬性設(shè)置初值的語句,如下所示:

...
foreach (AppUser dbUser in userMgr.Users) {     dbUser.City = Cities.PARIS;}
context.SaveChanges();
...

你不一定要為新屬性設(shè)置默認(rèn)值——這里只是想演示Configuration類中的Seed方法,可以用它更新數(shù)據(jù)庫中的已有用戶記錄。

警告:在用于真實(shí)項(xiàng)目的Seed方法中為屬性設(shè)置值時(shí)要小心,因?yàn)槟忝恳淮涡薷募軜?gòu)時(shí),都會(huì)運(yùn)用這些值,這會(huì)將自執(zhí)行上一次架構(gòu)更新之后,用戶設(shè)置的任何數(shù)據(jù)覆蓋掉。這里設(shè)置City屬性的值只是為了演示它能夠這么做。

修改數(shù)據(jù)庫上下文類

Configuration類中添加種植代碼的原因是我需要修改IdentityDbInit類。此時(shí),IdentityDbInit類派生于描述性命名的DropCreateDatabaseIfModelChanges<AppIdentityDbContext> 類,和你相像的一樣,它會(huì)在Code First類改變時(shí)刪除整個(gè)數(shù)據(jù)庫。清單15-6顯示了我對IdentityDbInit類所做的修改,以防止它影響數(shù)據(jù)庫。

清單15-6. 在AppIdentityDbContext.cs文件是阻止數(shù)據(jù)庫架構(gòu)變化

using System.Data.Entity;
using Microsoft.AspNet.Identity.EntityFramework;
using Users.Models;
using Microsoft.AspNet.Identity; 
namespace Users.Infrastructure {
    public class AppIdentityDbContext : IdentityDbContext<AppUser> {

        public AppIdentityDbContext() : base("IdentityDb") { }

        static AppIdentityDbContext() {
            Database.SetInitializer<AppIdentityDbContext>(new IdentityDbInit());
        }

        public static AppIdentityDbContext Create() {
             return new AppIdentityDbContext();
        }
    }

    }
}

我刪除了這個(gè)類中所定義的方法,并將它的基類改為NullDatabaseInitializer<AppIdentityDbContext> ,它可以防止架構(gòu)修改。

15.2.3 執(zhí)行遷移

剩下的事情只是生成并運(yùn)用遷移了。首先,在“Package Manager Console(包管理器控制臺(tái))”中執(zhí)行以下命令:

Add-Migration CityProperty

這創(chuàng)建了一個(gè)名稱為CityProperty的新遷移(我比較喜歡讓遷移的名稱反映出我所做的修改)。這會(huì)在文件夾中添加一個(gè)新的類文件,而且其命名會(huì)反映出該命令執(zhí)行的時(shí)間以及遷移名稱,例如,我的這個(gè)文件名稱為201402262244036_CityProperty.cs。該文件的內(nèi)容含有遷移期間Entity Framework修改數(shù)據(jù)庫的細(xì)節(jié),如清單15-7所示。

清單15-7. 201402262244036_CityProperty.cs文件的內(nèi)容

namespace Users.Migrations {
    using System;
    using System.Data.Entity.Migrations; 

    public partial class Init : DbMigration {
        public override void Up() {
            AddColumn("dbo.AspNetUsers", "City", c => c.Int(nullable: false));
        }

        public override void Down() {
            DropColumn("dbo.AspNetUsers", "City");
        }
    }
}

Up方法描述了在數(shù)據(jù)庫升級(jí)時(shí),需要對架構(gòu)所做的修改,在這個(gè)例子中,意味著要在AspNetUsers數(shù)據(jù)表中添加City數(shù)據(jù)列,該數(shù)據(jù)表是ASP.NET Identity數(shù)據(jù)庫用來存儲(chǔ)用戶記錄的。

最后一步是執(zhí)行遷移。無需啟動(dòng)應(yīng)用程序,只需在“Package Manager Console(包管理器控制臺(tái))”中運(yùn)行以下命令即可:

Update-Database –TargetMigration CityProperty

這會(huì)修改數(shù)據(jù)庫架構(gòu),并執(zhí)行Configuration.Seed方法中的代碼。已有用戶賬號(hào)會(huì)被保留,且增強(qiáng)了City屬性(我在Seed方法中已將其設(shè)置為“Paris”)。

15.2.4 測試遷移

為了測試遷移的效果,啟動(dòng)應(yīng)用程序,導(dǎo)航到/Home/UserProps URL,并以Identity中的用戶(例如Alice,口令MySecret)進(jìn)行認(rèn)證。一旦已被認(rèn)證,便會(huì)看到該用戶City屬性的當(dāng)前值,并可以對其進(jìn)行修改,如圖15-3所示。

圖15-3

圖15-3. 顯示和個(gè)性自定義用戶屬性

15.2.5 定義附加屬性

現(xiàn)在,已經(jīng)建立了數(shù)據(jù)庫遷移,我打算再定義一個(gè)屬性,這恰恰演示了如何處理持續(xù)不斷的修改,也為了演示Configuration.Seed方法更有用(至少無害)的示例。清單15-8顯示了我在AppUser類上添加了一個(gè)Country屬性。

清單15-8. 在AppUserModels.cs文件中添加另一個(gè)屬性

using System;
using Microsoft.AspNet.Identity.EntityFramework; 
namespace Users.Models {

    public enum Cities {
        LONDON, PARIS, CHICAGO
    }

        }
    }
}

我已經(jīng)添加了一個(gè)枚舉,它定義了國家名稱。還添加了一個(gè)輔助器方法,它可以根據(jù)City屬性選擇一個(gè)國家。清單15-9顯示了對Configuration類所做的修改,以使Seed方法根據(jù)City設(shè)置Country屬性,但只當(dāng)CountryNONE時(shí)才進(jìn)行設(shè)置(在遷移數(shù)據(jù)庫時(shí),所有用戶都是NONE,因?yàn)镋ntity Framework會(huì)將枚舉列設(shè)置為枚舉的第一個(gè)值)。

清單15-9. 在Configuration.cs文件中修改數(shù)據(jù)庫種子

using System.Data.Entity.Migrations;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Users.Infrastructure;
using Users.Models; 
namespace Users.Migrations {

    internal sealed class Configuration
            : DbMigrationsConfiguration<AppIdentityDbContext> {

        public Configuration() {
            AutomaticMigrationsEnabled = true;
            ContextKey = "Users.Infrastructure.AppIdentityDbContext";
        }

        protected override void Seed(AppIdentityDbContext context) {

            AppUserManager userMgr = new AppUserManager(new UserStore<AppUser>(context));
            AppRoleManager roleMgr = new AppRoleManager(new RoleStore<AppRole>(context)); 

            string roleName = "Administrators";
            string userName = "Admin";
            string password = "MySecret";
            string email = "admin@example.com";

            if (!roleMgr.RoleExists(roleName)) {
                 roleMgr.Create(new AppRole(roleName));
            }

            AppUser