claim alue_claim是什么意思_claim用法

电脑杂谈  发布时间:2017-05-15 21:13:24  来源:网络整理

claim alue

Asp.Net Identity学习笔记+MVC5默认项目解析_基础用法

Asp.Net Identity学习笔记+MVC5默认项目解析_授权&Claim

最常用的授权就是给Controller或Action打上[Authorize]标签

没错这个就是MVC的授权过滤器

看下他的授权关键源码

  1. protected virtual bool AuthorizeCore(HttpContextBase httpContext)
  2. {
  3. if (httpContext == null)
  4. {
  5. throw new ArgumentNullException("httpContext");
  6. }
  7. IPrincipal user = httpContext.User;
  8. return user.Identity.IsAuthenticated && (this._usersSplit.Length <= 0 || this._usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase)) && (this._rolesSplit.Length <= 0 || this._rolesSplit.Any(new Func<string, bool>(user.IsInRole)));
  9. }

我个人猜测关键大概就在最后一行user.Identity.IsAuthenticated,如果用户验证成功则为true,这是个只读属性,肯定会在某个地方设置为true才能授权成功.

就拿之前的登入案例的第一段代码说,授权的关键就在于

  1. ClaimsIdentity ident = await UserManager.CreateIdentityAsync(user,DefaultAuthenticationTypes.ApplicationCookie);
  2. AuthManager.SignOut();
  3. AuthManager.SignIn(new AuthenticationProperties {IsPersistent = false}, ident);
  4. return Redirect(returnUrl);

创建用户标识(ClaimsIdentity),保存到user.Identity(通过方法AuthManager.SignIn),ClaimsIdentity实现IIdentity(它有个成员IsAuthenticated).

看下ClaimsIdentity源码

  1. public virtual bool IsAuthenticated
  2. {
  3. get
  4. {
  5. return !string.IsNullOrEmpty(this.m_authenticationType);
  6. }
  7. }

代码中是判断授权类别字段是否存在,也就是当你创建了有授权类别的ClaimsIdentity就算是授权了

角色授权是更细粒度的授权,上面简单使用[Authorize]只区分了登入用户和未登入用户.

使用角色授权可以赋予用户角色,并限制角色的访问,最简单的方式是给Action添加[Authorize(Roles="Role1,Role2")]限制能访问该Action的用户必须是XXX角色.

角色的使用方法与用户很类似,都要用到IdentityRole和RoleManager

在MVC默认项目中并没有用到角色授权,但我也简单介绍一下,如果想详细学习请看

对应的表为AspNetRoles

用户与角色是多对多关心,所以还有一个AspNetUserRoles

  1. public class ApplicationRole : IdentityRole
  2. {
  3. //可扩展字段
  4. }

IdnetityRole的默认成员

名称 描述

  1. public class ApplicationRoleManager : RoleManager<ApplicationRole>, IDisposable
  2. {
  3. public ApplicationRoleManager(RoleStore<ApplicationRole> store) : base(store) { }
  4. //同样地,用于Owin
  5. public static ApplicationRoleManager Create(
  6. IdentityFactoryOptions<ApplicationRoleManager> options,
  7. IOwinContext context)
  8. {
  9. return new ApplicationRoleManager(new RoleStore<ApplicationRole>(context.Get<ApplicationDbContext>()));
  10. }
  11. }

RoleManager常用成员

名称 描述

注意

你可以自己继承IdentityRole扩展自己的Role,但是默认情况下EF Code First会映射这个继承关系,直接的影响是你的AspNetRoles表会多出一个字段Discriminator,用于区分你的Role和IdentityRole.

我尝试隐藏这个字段不管是用Fluent Api方式还是使用模型注解都失败了,求指导.

有人可能会问为什么继承IdentityUser自定用户的时候为什么不会自动生成Discriminator,其实我也很疑惑,我初步的猜想是因为用的上下文是ApplicationDbContext : IdentityDbContext<ApplicationUser>,手动指定了要用的用户类,这个IdentityDbContext还有个重载IdentityDbContext<TUser, TRole, TKey, TUserLogin, TUserRole, TUserClaim>,我尝试过IdentityDbContext<ApplicationUser, ApplicationRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>(手动指定我的用户类和角色类,但最后还是报错,求指点)

claim alue_claim用法_claim是什么意思

根据试验用户名,Id和角色信息会保存到浏览器Cookie中,所以当更新某个用户的角色信息后要记得更新它浏览器的Cookie

当授权检测失败(用户未登入,用户不是XX角色…)都会跳转到LoginPath(在app.UseCookieAuthentication设置的),所以某个已登入用户访问未授权页面也会跳转到这个LoginPath.你可以添加一小段代码反馈正确的信息给这个用户

  1. public ActionResult Login(string returnUrl) {
  2. if (HttpContext.User.Identity.IsAuthenticated) {
  3. return View("Error", new string[] { "Access Denied" });
  4. }
  5. //省略

这部分我讲从较具体的层面(代码)解释声明,其实我是看不懂别人的.

虽然Claims翻译成声明但实际这个特性与声明一词好像没什么关系.因此下文我都尽量地使用Claims.

先亮一个定义

声明(Claims)是关于用户的一些信息片段

另外,我打算使用上面角色授权的例子来解释Claims,因为角色授权内部已经用到了Claims.

在开始解释之前先介绍几个比较重要的类/接口,前面有用户这些类/接口

这个安全上下文对象包含了上面的identity以及一些角色和组的信息,每一个线程都会关联一个Principal的对象,但是这个对象是属性进程或者AppDomain级别的。claim alue

在控制器中User,HttpContext.User,System.Web.HttpContext.Current.User,都是同一个对象IPrincipal(实际是System.Security.Claims.ClaimsPrincipal类型)

名称 描述

通过User.Identity能获取

名称 描述

其实现类

名称 描述

名称 描述

声明提供者不只有应用程序本身,也可以通过外部提供声明,比如第三方登入可以提供声明

下面就把上面的代码搬下来讲

  1. ClaimsIdentity ident = await UserManager.CreateIdentityAsync(user,DefaultAuthenticationTypes.ApplicationCookie);
  2. AuthManager.SignOut();
  3. AuthManager.SignIn(new AuthenticationProperties {IsPersistent = false}, ident);
  4. return Redirect(returnUrl);

首先创建Identity

使用UserManager.CreateIdentityAsync=>内部调用ClaimsIdentityFactory.CreateAsyncIdentity关键的创建过程在这个方法内

ClaimsIdentity claimsIdentity = new ClaimsIdentity(authenticationType, this.UserNameClaimType, this.RoleClaimType);

claimsIdentity.AddClaim(new Claim(this.UserIdClaimType, this.ConvertIdToString(user.Id), "http://.w3.org/2001/XMLSchema#string"));

claimsIdentity.AddClaim(new Claim(this.UserNameClaimType, user.UserName, "http://.w3.org/2001/XMLSchema#string"));

claimsIdentity.AddClaim(new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "ASP.NET Identity", "http://.w3.org/2001/XMLSchema#string"));

if (manager.SupportsUserSecurityStamp)

{

claimsIdentity.AddClaim(new Claim(this.SecurityStampClaimType, await manager.GetSecurityStampAsync(user.Id).WithCurrentCulture<string>()));

}

//...

加了4个Claim,这四个Claim用来保存用户Id,用户名,identityprovider(不知道用来干嘛),SecurityStamp(不知道用来干嘛).

这样直接造成的影响是

技术分享

展开其中一个看看

技术分享

到这里应该能理解声明(Claims)是关于用户的一些信息片段这句话吧.传统的做在登入后把用户信息保存到Session中(可能直接保存User类或者新创建一个UserInfo类保存之),在用户再访问网站时候能获取这个用户的信息.现在直接使用Claims来添加用户的信息片段,使用上更加的灵活,细腻,可扩展.

在使用Identity时候,可以使用这种方式限制访问的用户,实际上内部用到了Claims

  1. [Authorize(Roles ="角色1,角色2",Users="用户1,用户2")]
  2. public ActionResult ActionName(){}

下面代码搬运自AuthorizeAttribute的AuthorizeCore最后一行代码,这是授权过滤器的核心

  1. return user.Identity.IsAuthenticated && (this._usersSplit.Length <= 0 || this._usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase)) && (this._rolesSplit.Length <= 0 || this._rolesSplit.Any(new Func<string, bool>(user.IsInRole)));
  2. //_usersSplit,_rolesSplit是Users,Roles字符串用逗号切割生成的字符串数组

解释下这段代码

用户必须登入

当前用户的用户名必须存在于_usersSplit

用户必须在_rolesSplit用户组中

IsInRole

user.IsInRole是IPrincipal中的方法

  1. public virtual bool IsInRole(string role)
  2. {
  3. for (int i = 0; i < this.m_identities.Count; i++)
  4. {
  5. //查看当前用户的Identity中是否有RoleClaimType声明,且这个声明的值为role
  6. if (this.m_identities[i] != null && this.m_identities[i].HasClaim(this.m_identities[i].RoleClaimType, role))
  7. {
  8. return true;
  9. }
  10. }
  11. return false;
  12. }

看下默认情况下的RoleClaimType

技术分享

再看下HasClaim

  1. public virtual bool HasClaim(string type, string value)
  2. {
  3. if (type == null)
  4. {
  5. throw new ArgumentNullException("type");
  6. }
  7. if (value == null)
  8. {
  9. throw new ArgumentNullException("value");
  10. }
  11. //遍历当前Identity所有Claims,找到类型为type且值为value,如果找到了则返回true
  12. foreach (Claim current in this.Claims)
  13. {
  14. if (current != null && current != null && string.Equals(current.Type, type, StringComparison.OrdinalIgnoreCase) && string.Equals(current.Value, value, StringComparison.Ordinal))
  15. {
  16. return true;
  17. }
  18. }
  19. return false;
  20. }

由于授权内部是基于Claim的,所以可以在程序运行时动态地给用户添加角色User.Identity.Claims.Add(new Claim(ClaimTypes.Role, "Role")).

你甚至可以自定义Claim授权器

  1. public class ClaimsAccessAttribute : AuthorizeAttribute {
  2. public string Issuer { get; set; }
  3. public string ClaimType { get; set; }
  4. public string Value { get; set; }
  5. protected override bool AuthorizeCore(HttpContextBase context) {
  6. return context.User.Identity.IsAuthenticated
  7. && context.User.Identity is ClaimsIdentity
  8. && ((ClaimsIdentity)context.User.Identity).HasClaim(x =>
  9. x.Issuer == Issuer && x.Type == ClaimType && x.Value == Value
  10. );
  11. }
  12. }
  13. [ClaimsAccess(Issuer="RemoteClaims", ClaimType=ClaimTypes.PostalCode,
  14. Value="DC 20500")]
  15. public string OtherAction() {
  16. return "This is the protected action";
  17. }

最后用Signin登入,内部实现我没研究大概会去影响Cookie

Claim类有个Type成员,他是字符串类型,通常都是用一个Url表示

技术分享

你创建自己的Claim时候可以自定义Type,也可以用内置的一些字符串(保存在System.Security.Claims.ClaimTypes)

其实上面说的声明什么的都是集成在Asp.Net中的并不是Identity发明的

他们的命名空间大都是System.Security.Claims和System.Security.Principal

Identity包最多写了一些扩展方法而已

Asp.Net Identity学习笔记+MVC5默认项目解析_授权&Claim


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-47329-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      热点图片
      拼命载入中...