`

ASP.NET Identity 使用简介

阅读更多

1. 什么是 ASP.NET Identity

ASP.NET Identity 是微软推出,用于在ASP.NET应用中管理用户的组件。

 

The mainstay for user management in recent years has been ASP.NET Membership, which has suffered from design choices. The biggest limitation is that the schema used to store the data worked only with SQL Server and was difficult to extend without re-implementing a lot of provider classes. The schema itself was overly complex, which made it harder to implement changes than it should have been.

  --Pro ASP.NET MVC 5 Platform

 

2. 如何配置ASP.NET Identity with MySQL

2.1 配置ASP.NET Identity

2.1.1 安装相应的组件包

Microsoft.AspNet.Identity.EntityFramework

Microsoft.AspNet.Identity.OWIN

Microsoft.Owin.Host.SystemWeb

 

2.1.2 自定义核心组件

$ User model

默认的user model是 IdentityUser(Microsoft.AspNet.Identity.EntityFramework)。这个类有12个内建的属性,如 Id、UserName、PasswordHash、Email等

一般,根据业务需求,我们需要其它额外的属性。我们可以创建一个继承自IdentityUser的自定义类,在这个自定义类中添加额外的属性。

using Microsoft.AspNet.Identity.EntityFramework

public class AppUser : IdentityUser {
    // 在这里添加额外的属性
}

 

$ DB Context

一般我们需要改变Identity用到的数据库表的名称。默认的数据库表为:AspNetUsers、AspNetUserRoles、AspNetUserLogins、AspNetUserCliams、AspNetRoles。

using System.Data.Entity;
using Microsoft.Asp.Net.Identity.EntityFramework;
public class AppIdentityDbContext : IdentityDbContext<AppUser> {
    public AppIdentityDbContext() : base("IdentityDb") { }
    public AppIdentityDbContext(string connectionString)
        : base(connectionString) {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<AppUser>().ToTable("user");
        modelBuilder.Entity<IdentityRole>().ToTable("role");
        modelBuilder.Entity<IdentityUserRole>().ToTable("userrole");
        modelBuilder.Entity<IdentityUserClaim>().ToTable("userclaim");
        modelBuilder.Entity<IdentituUserLogin>().ToTable("userlogin");
    }
}

 

$ DB 初始化

如果你不熟悉Identity的数据库表的结构,可以通过代码让Identity自动创建。

如果你比较熟悉,那我推荐用专业的数据库管理工具来创建,如MySQL Workbench。

代码示例。一般初始化代码只需要执行一次,好好斟酌策略,防止数据被删。

using System.Data.Entity;
public class AppIdentityDbContext : IdentityDbContext<AppUser> {
    ...
    static AppIdentityDbContext() {
        Database.SetInitializer<AppIdentityDbContext>(new IdentityDbInit());
    }
}

 

using System.Data.Entity;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;

public class IdentityDbInit : DropCreateDatabaseAlways<AppIdentityDbContext> {
    protectedd override void Seed(AppIdentityDbContext context) {
        this.InitAdmin(context);
        base.Seed(context);
    }

    public void InitAdmin(AppIdentityDbContext context) {
        string adminName = "admin";
        string adminPassword = "changeme";
        string adminRoleName = "Administrators";

        // 创建用户
        UserManager<AppUser> userManager = new UserManager<AppUser>(
            new UserStore<AppUser>(context));
        var user = new AppUser { UserName = adminName };
        userManager.Create(user, adminPassword);

        // 创建角色
        RoleManager<IdentityRole> roleManager = new RoleManager<IdentityRole>(
            new RoleStore<IdentityRole>(context));
        var adminRole = roleManager.Create(new IdentityRole(adminRoleName));

        // 给用户赋予角色
        userManager.AddToRole(user.Id, adminRoleName);
    }
}

 

$ 配置

using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Owin;

public class IdentityConfig {
    public void Configuration(IAppBuilder app) {
        app.CreatePerOwinContext<AppIdentityDbContext>(() => new AppIdentityDbContext());
        app.CreatePerOwinContext<UserManager<AppUser>>(
            (o, c) => new UserManager<AppUser>(new UserStore<AppUser>(
                c.Get<AppIdentityDbContext>())));
        app.CreatePerOwinContext<RoleManager<IdentityRole>>(
            (o, c) => new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(
                c.Get<AppIdentityDbContext>())));

        app.UseCookieAuthentication(new CookieAuthenticationOptions {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login")
        });
    }
}

 

2.1.3 配置web.config

<configuration>
  <appSettings>
    <add key="owin:AppStartup" value="IdentityConfig" />
    ...
  </appSettings>
  ...
</configuration>

 

2.2 配置MySQL DB

2.2.1 安装相应的组件包

MySql.Data.Entity

 

2.2.2 配置web.config

 

<configuration>
  <configSections>
    <section name="entityFramework"
	         type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework">
  </configSections>
  <system.data>
    <DbProviderFactories>
	  <remove invariant="MySql.Data.MySqlClient" />
	  <add name="MySQL Data Provider"
	       invariant="MySql.Data.MySqlClient"
		   description=".Net Framework Data Provider for MySQL"
		   type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data" />
	</DbProviderFactories>
  </system.data>
  <connectionStrings>
    <add name="IdentityDb"
	     connectionString="server=192.168.0.9;user id=tester;password=changeme;database=IdentityDb"
		 providerName="MySql.Data.MySqlClient" />
  </connectionStrings>
  <entityFramework>
    <providers>
	  <provider invariantName="MySql.Data.MySqlClient"
	  type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6" />
	</providers>
  </entityFramework>
</configuration>

 

2.2.3 创建DB

方法一:创建一个没有表的空DB,通过代码让Identity自动创建表。(见上文)

方法二:创建一个带有所有Identity相关表的DB

 

$ User


 

CREATE TABLE `user` (
  `Id` varchar(128) NOT NULL,
  `Email` varchar(256) DEFAULT NULL,
  `EmailConfirmed` tinyint(1) NOT NULL,
  `PasswordHash` longtext,
  `SecurityStamp` longtext,
  `PhoneNumber` longtext,
  `PhoneNumberConfirmed` tinyint(1) NOT NULL,
  `TwoFactorEnabled` tinyint(1) NOT NULL,
  `LockoutEndDateUtc` datetime DEFAULT NULL,
  `LockoutEnabled` tinyint(1) NOT NULL,
  `AccessFailedCount` int(11) NOT NULL,
  `UserName` varchar(256) NOT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

 

$ Role


 

CREATE TABLE `role` (
  `Id` varchar(128) NOT NULL,
  `Name` varchar(256) NOT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

 

$ UserRole


 

CREATE TABLE `userrole` (
  `UserId` varchar(128) NOT NULL,
  `RoleId` varchar(128) NOT NULL,
  PRIMARY KEY (`UserId`,`RoleId`),
  KEY `IdentityRole_Users` (`RoleId`),
  CONSTRAINT `AppUser_Roles` FOREIGN KEY (`UserId`) REFERENCES `user` (`Id`)
    ON DELETE CASCADE ON UPDATE NO ACTION,
  CONSTRAINT `IdentityRole_Users` FOREIGN KEY (`RoleId`) REFERENCES `role` (`Id`)
    ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8

 

$ UserClaim


 

 

CREATE TABLE `userclaim` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `UserId` varchar(128) NOT NULL,
  `ClaimType` longtext,
  `ClaimValue` longtext,
  PRIMARY KEY (`Id`),
  UNIQUE KEY `Id` (`Id`),
  KEY `UserId` (`UserId`),
  CONSTRAINT `AppUser_Claims` FOREIGN KEY (`UserId`) REFERENCES `user` (`Id`)
    ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8

 

$ UserLogin



 

CREATE TABLE `userlogin` (
  `LoginProvider` varchar(128) NOT NULL,
  `ProviderKey` varchar(128) NOT NULL,
  `UserId` varchar(128) NOT NULL,
  PRIMARY KEY (`LoginProvider`,`ProviderKey`,`UserId`),
  KEY `AppUser_Logins` (`UserId`),
  CONSTRAINT `AppUser_Logins` FOREIGN KEY (`UserId`) REFERENCES `user` (`Id`)
    ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8

 


 

3. 如何使用ASP.NET Identity

3.1 认证(Authenticate)

using System.Security.Claims;
using System.Web;
using System.Web.Mvc;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;

public class AccountController : Controller {
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public ActionResult Login(string name, string password, string returnUrl) {
        var userManager = HttpContext.GetOwinContext()
            .GetUserManager<UserManager<AppUser>>();
        var authManager = HttpContext.GetOwinContext().Authentication;
        var user = userManager.Find(name, password);
        if (user == null) {
            // Invalid name or password
        }
        else {
            ClaimsIdentity identity = userManager.CreateIdentity(
                user, DefaultAuthenticationTypes.ApplicationCookie);
            authManager.SignOut();
            authManager.SignIn(identity);
            return Redirect(returnUrl);
        }

        return View();
    }
}

 

3.2 用户操作

using System.Security.Principal;
using System.Web;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;

var userManager = HttpContext.Current.GetOwinContext()
    .GetUserManager<UserManager<AppUser>>();

// 获取当前用户
IPrincipal principal = HttpContext.Current.User;
AppUser user = userManager.FindByName(principal.Identity.Name);

// 创建用户
var newUser = new AppUser { UserName = "Alice" };
varr password = "changeme";
userManager.Create(newUser, password);

// 删除用户
userManager.Delete(user);

// 修改用户信息
user.Email = "huangc126@126.com";
user.PasswordHash = userManager.PasswordHasher.HashPassword("secret");

 

3.3 角色管理

using System.Web;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;

var roleManager = HttpContext.Current.GetOwinContext()
    .GetUserManager<RoleManager<IdentityRole>>();

// 创建角色
var newRole = new IdentityRole { Name = "Admin" };
roleManager.Create(newRole);

// 将角色授予用户
userManager.AddToRole(userId, role: "Admin");

// 移除用户的角色
userManager.RemoveFromRole(userId, role: "Admin");

// 删除角色
var role = roleManager.FindByName("Admin");
roleManager.Delete(role);

 

3.4 授权(Authorization)

3.4.1 基于角色的授权

using System.Web.Mv;

[Authorize(Roles = "Administrators")]
public class AdminController : Controller {
    ...
}

 

3.4.2 基于声明(Claim)的授权

using System.Security.Claims;
using System.Web;
using System.Web.Mvc;

[ClaimsAccess(Issuer = "RemoteClaims", ClaimType = ClaimTypes.PostalCode, Value = "123456")]
public ActionResult Action() {
    ...
}

public class ClaimsAccessAttribute : AuthorizeAttribute {
    public string Issuer { get; set; }
	public string ClaimType { get; set; }
	public string Value { get; set; }
	
	protected override bool AuthorizeCore(HttpContextBase context) {
	    return context.User.Identity.IsAuthenticated
		    && context.User.Identity is ClaimsIdentity
			&& ((ClaimnsIdentity)context.User.Identity).HasClaim(
			    c => c.Issuer == this.Issuer
				    && c.Type == this.ClaimType
					&& c.Value == this.Value);
	}
}

 

 

4. 小结

ASP.NET Identity非常灵活,支持各种扩展,对中小型系统来说足够用了。虽然看上去有点麻烦,但即使是小系统,我也建议用Identity。因为自己去搞一套太麻烦,又容易出错。我们应该把更多的精力花在业务实现上,而不是去抠底层技术细节。

  • 大小: 14.7 KB
  • 大小: 5.5 KB
  • 大小: 4.9 KB
  • 大小: 6.6 KB
  • 大小: 5.6 KB
  • 大小: 24.6 KB
0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics