Asp.Net Core Identity 骚断腿的究极魔改实体类

前言

默认的 Identity 实体类型在大多数时候已经基本够用,很多时候也只是稍微在 IdentityUser 类中增加一些自定义数据字段,比如头像。这次,我要向园友隆重介绍我魔改之后的 Identity 实体类,能支持一些特别风骚的操作。当然也完全兼容内置的 UserManager、RoleManager 和 SignInManager,毕竟也是从内置类型继承扩展出来的。

正文

魔改的实体类基于一组我自定义实体接口,这组接口我也实现了一组打包好的基础类型。因为 Identity 系列实体类型已经存在,而 C# 不支持多重继承,所以只能把这些代码在魔改的 Identity 实体类中粘贴几次了。

先来看看这些基本接口吧:

  1     /// <summary>
  2     /// 软删除接口
  3     /// </summary>
  4     public interface ILogicallyDeletable
  5     {
  6         /// <summary>
  7         /// 逻辑删除标记
  8         /// </summary>
  9         bool IsDeleted { get; set; }
 10     }
 11
 12     /// <summary>
 13     /// 活动状态标记接口
 14     /// </summary>
 15     public interface IActiveControllable
 16     {
 17         /// <summary>
 18         /// 活动状态标记
 19         /// </summary>
 20         bool? Active { get; set; }
 21     }
 22
 23     /// <summary>
 24     /// 乐观并发接口
 25     /// </summary>
 26     public interface IOptimisticConcurrencySupported
 27     {
 28         /// <summary>
 29         /// 行版本,乐观并发锁
 30         /// </summary>
 31         [ConcurrencyCheck]
 32         string ConcurrencyStamp { get; set; }
 33     }
 34
 35     /// <summary>
 36     /// 插入顺序记录接口
 37     /// </summary>
 38     public interface IStorageOrderRecordable
 39     {
 40         /// <summary>
 41         /// 非自增顺序字段作为主键类型
 42         /// 应该在此列建立聚集索引避免随机的字段值导致数据库索引性能下降
 43         /// 同时保存数据插入先后的信息
 44         /// </summary>
 45         long InsertOrder { get; set; }
 46     }
 47
 48     /// <summary>
 49     /// 创建时间记录接口
 50     /// </summary>
 51     public interface ICreationTimeRecordable
 52     {
 53         /// <summary>
 54         /// 实体创建时间
 55         /// </summary>
 56         DateTimeOffset CreationTime { get; set; }
 57     }
 58
 59     /// <summary>
 60     /// 最后修改时间记录接口
 61     /// </summary>
 62     public interface ILastModificationTimeRecordable
 63     {
 64         /// <summary>
 65         /// 最后一次修改时间
 66         /// </summary>
 67         DateTimeOffset LastModificationTime { get; set; }
 68     }
 69
 70     /// <summary>
 71     /// 创建人id记录接口
 72     /// </summary>
 73     /// <typeparam name="TIdentityKey">创建人主键类型</typeparam>
 74     public interface ICreatorRecordable<TIdentityKey>
 75         where TIdentityKey : struct, IEquatable<TIdentityKey>
 76     {
 77         /// <summary>
 78         /// 创建人Id
 79         /// </summary>
 80         TIdentityKey? CreatorId { get; set; }
 81     }
 82
 83     /// <summary>
 84     /// 创建人记录接口
 85     /// </summary>
 86     /// <typeparam name="TIdentityKey">创建人主键类型</typeparam>
 87     /// <typeparam name="TIdentityUser">创建人类型</typeparam>
 88     public interface ICreatorRecordable<TIdentityKey, TIdentityUser> : ICreatorRecordable<TIdentityKey>
 89         where TIdentityKey : struct , IEquatable<TIdentityKey>
 90         where TIdentityUser : IEntity<TIdentityKey>
 91     {
 92         /// <summary>
 93         /// 创建人
 94         /// </summary>
 95         TIdentityUser Creator { get; set; }
 96     }
 97
 98     /// <summary>
 99     /// 上次修改人id记录接口
100     /// </summary>
101     /// <typeparam name="TIdentityKey">上次修改人主键类型</typeparam>
102     public interface ILastModifierRecordable<TIdentityKey>
103         where TIdentityKey : struct, IEquatable<TIdentityKey>
104     {
105         /// <summary>
106         /// 上一次修改人Id
107         /// </summary>
108         TIdentityKey? LastModifierId { get; set; }
109     }
110
111     /// <summary>
112     /// 上次修改人记录接口
113     /// </summary>
114     /// <typeparam name="TIdentityKey">上次修改人主键类型</typeparam>
115     /// <typeparam name="TIdentityUser">上次修改人类型</typeparam>
116     public interface ILastModifierRecordable<TIdentityKey, TIdentityUser> : ILastModifierRecordable<TIdentityKey>
117         where TIdentityKey : struct, IEquatable<TIdentityKey>
118         where TIdentityUser : IEntity<TIdentityKey>
119     {
120         /// <summary>
121         /// 上一次修改人
122         /// </summary>
123         TIdentityUser LastModifier { get; set; }
124     }

这些基本接口每一个都对应了一个基本功能。还有一个稍微复杂的树形数据结构接口:

 1     /// <summary>
 2     /// 树形数据接口
 3     /// </summary>
 4     /// <typeparam name="T">节点数据类型</typeparam>
 5     public interface ITree<T>
 6     {
 7         /// <summary>
 8         /// 父节点
 9         /// </summary>
10         T Parent { get; set; }
11
12         /// <summary>
13         /// 子节点集合
14         /// </summary>
15         IList<T> Children { get; set; }
16
17         /// <summary>
18         /// 节点深度,根的深度为0
19         /// </summary>
20         int Depth { get; }
21
22         /// <summary>
23         /// 是否是根节点
24         /// </summary>
25         bool IsRoot { get; }
26
27         /// <summary>
28         /// 是否是叶节点
29         /// </summary>
30         bool IsLeaf { get; }
31
32         /// <summary>
33         /// 是否有子节点
34         /// </summary>
35         bool HasChildren { get; }
36
37         /// <summary>
38         /// 节点路径(UNIX路径格式,以“/”分隔)
39         /// </summary>
40         string Path { get; }
41     }

然后是打包接口,主要是把基本接口打包到一个统一接口,方便批量使用:

 1     /// <summary>
 2     /// 实体接口
 3     /// </summary>
 4     public interface IEntity {}
 5
 6     /// <summary>
 7     /// 泛型实体接口,约束Id属性
 8     /// </summary>
 9     public interface IEntity<TKey> : IEntity
10         where TKey : IEquatable<TKey>
11     {
12         TKey Id { get; set; }
13     }
14
15     /// <summary>
16     /// 领域实体接口,主要是整合各个小接口
17     /// </summary>
18     public interface IDomainEntity : IEntity
19         , ILogicallyDeletable
20         , ICreationTimeRecordable
21         , ILastModificationTimeRecordable
22         , INotifyPropertyChanged
23         , INotifyPropertyChangedExtension
24         , IPropertyChangeTrackable
25     {}
26
27     /// <summary>
28     /// 泛型领域实体接口
29     /// </summary>
30     public interface IDomainEntity<TKey> : IEntity<TKey>
31         , IDomainEntity
32         where TKey : struct, IEquatable<TKey>
33     {}

树形数据结构也有一套:

 1     /// <summary>
 2     /// 树形实体接口
 3     /// </summary>
 4     /// <typeparam name="T">实体类型</typeparam>
 5     public interface ITreeEntity<T> : IEntity, ITree<T>
 6     {
 7     }
 8
 9     /// <summary>
10     /// 树形实体接口
11     /// </summary>
12     /// <typeparam name="TKey">主键类型</typeparam>
13     /// <typeparam name="TEntity">实体类型</typeparam>
14     public interface ITreeEntity<TKey, TEntity> : ITreeEntity<TEntity>, IEntity<TKey>
15     where TKey : IEquatable<TKey>
16     where TEntity : ITreeEntity<TKey, TEntity>
17     {
18     }
19
20     /// <summary>
21     /// 树形领域实体接口
22     /// </summary>
23     /// <typeparam name="T">数据类型</typeparam>
24     public interface IDomainTreeEntity<T> :
25         IDomainEntity
26         , ITreeEntity<T>
27     {
28     }
29
30     /// <summary>
31     /// 树形领域实体接口
32     /// </summary>
33     /// <typeparam name="TKey">主键类型</typeparam>
34     /// <typeparam name="TEntity">树形实体类型</typeparam>
35     public interface IDomainTreeEntity<TKey, TEntity> :
36         IDomainTreeEntity<TEntity>
37         , IDomainEntity<TKey>
38         , ITreeEntity<TKey, TEntity>
39
40         where TKey : struct, IEquatable<TKey>
41         where TEntity : IDomainTreeEntity<TKey, TEntity>
42     {
43         TKey? ParentId { get; set; }
44     }

最后还有几个特别用处的接口:

 1     /// <summary>
 2     /// 跟踪属性的变更
 3     /// </summary>
 4     public interface IPropertyChangeTrackable
 5     {
 6         /// <summary>
 7         /// 判断指定的属性或任意属性是否被变更过
 8         /// </summary>
 9         /// <param name="names">指定要判断的属性名数组,如果为空(null)或空数组则表示判断任意属性</param>
10         /// <returns>
11         ///    <para>如果指定的<paramref name="names"/>参数有值,当只有参数中指定的属性发生过更改则返回真(True),否则返回假(False)</para>
12         ///    <para>如果指定的<paramref name="names"/>参数为空(null)或空数组,当实体中任意属性发生过更改则返回真(True),否则返回假(False)</para>
13         ///    </returns>
14         bool HasChanges(params string[] names);
15
16         /// <summary>
17         /// 获取实体中发生过变更的属性集
18         /// </summary>
19         /// <returns>如果实体没有属性发生过变更,则返回空白字典,否则返回被变更过的属性键值对</returns>
20         IDictionary<string, object> GetChanges();
21
22         /// <summary>
23         /// 重置指定的属性或任意属性变更状态(为未变更)
24         /// </summary>
25         /// <param name="names">指定要重置的属性名数组,如果为空(null)或空数组则表示重置所有属性的变更状态(为未变更)</param>
26         void ResetPropertyChangeStatus(params string[] names);
27     }
28
29     /// <summary>
30     /// 多对多导航实体接口
31     /// </summary>
32     /// <typeparam name="TIdentityKey">身份实体主键类型</typeparam>
33     /// <typeparam name="TIdentityUser">身份实体类型</typeparam>
34     public interface IManyToManyReferenceEntity<TIdentityKey, TIdentityUser> : IManyToManyReferenceEntity<TIdentityKey>
35         , ICreatorRecordable<TIdentityKey, TIdentityUser>
36         where TIdentityKey : struct, IEquatable<TIdentityKey>
37         where TIdentityUser : IEntity<TIdentityKey>
38     {
39     }
40
41     /// <summary>
42     /// 多对多导航实体接口
43     /// </summary>
44     /// <typeparam name="TIdentityKey">身份实体主键类型</typeparam>
45     public interface IManyToManyReferenceEntity<TIdentityKey> : IManyToManyReferenceEntity
46         , ICreatorRecordable<TIdentityKey>
47         where TIdentityKey : struct, IEquatable<TIdentityKey>
48     {
49     }
50
51     /// <summary>
52     /// 多对多导航实体接口
53     /// </summary>
54     public interface IManyToManyReferenceEntity : IEntity
55         , ICreationTimeRecordable
56     {
57     }

至此,基本上用到的接口就定义好了,接下来就是魔改 Identity 实体类,这里以 IdentityRole 为例,其他的可以到我的项目中查看,大同小异:

  1     public class ApplicationRole : ApplicationRole<int, ApplicationUser, ApplicationRole, ApplicationUserRole, ApplicationRoleClaim>
  2         , IStorageOrderRecordable
  3     {
  4         public ApplicationRole() { }
  5         public ApplicationRole(string roleName) => Name = roleName;
  6
  7         public virtual long InsertOrder { get; set; }
  8     }
  9
 10     public abstract class ApplicationRole<TKey, TIdentityUser, TIdentityRole, TUserRole, TRoleClaim> : IdentityRole<TKey>
 11         , IDomainTreeEntity<TKey, TIdentityRole>
 12         , IOptimisticConcurrencySupported
 13         , ICreatorRecordable<TKey, TIdentityUser>
 14         , ILastModifierRecordable<TKey, TIdentityUser>
 15         where TKey : struct, IEquatable<TKey>
 16         where TIdentityUser : IEntity<TKey>
 17         where TUserRole : ApplicationUserRole<TKey, TIdentityUser, TIdentityRole>
 18         where TRoleClaim : ApplicationRoleClaim<TKey, TIdentityUser, TIdentityRole>
 19         where TIdentityRole : ApplicationRole<TKey, TIdentityUser, TIdentityRole, TUserRole, TRoleClaim>
 20     {
 21         #region 重写基类属性使属性变更通知事件生效
 22
 23         public override TKey Id { get => base.Id; set => base.Id = value; }
 24         public override string ConcurrencyStamp { get => base.ConcurrencyStamp; set => base.ConcurrencyStamp = value; }
 25         public override string Name { get => base.Name; set => base.Name = value; }
 26         public override string NormalizedName { get => base.NormalizedName; set => base.NormalizedName = value; }
 27
 28         #endregion
 29
 30         public string Description { get; set; }
 31
 32         /// <summary>
 33         /// 需要使用.Include(r => r.UserRoles).ThenInclude(ur => ur.Role)预加载或启用延迟加载
 34         /// </summary>
 35         [NotMapped]
 36         public virtual IEnumerable<TIdentityUser> Users => UserRoles?.Select(ur => ur.User);
 37
 38         #region 导航属性
 39
 40         public virtual List<TUserRole> UserRoles { get; set; } = new List<TUserRole>();
 41
 42         public virtual List<TRoleClaim> RoleClaims { get; set; } = new List<TRoleClaim>();
 43
 44         #endregion
 45
 46         #region IDomainTreeEntity成员
 47
 48         public virtual TKey? ParentId { get; set; }
 49
 50         #endregion
 51
 52         #region IEntity成员
 53
 54         public virtual bool? Active { get; set; } = true;
 55         public virtual bool IsDeleted { get; set; }
 56         public virtual DateTimeOffset CreationTime { get; set; } = DateTimeOffset.Now;
 57         public virtual DateTimeOffset LastModificationTime { get; set; } = DateTimeOffset.Now;
 58
 59         #endregion
 60
 61         #region IDomainEntity成员
 62
 63         public virtual TKey? CreatorId { get; set; }
 64         public virtual TIdentityUser Creator { get; set; }
 65         public virtual TKey? LastModifierId { get; set; }
 66         public virtual TIdentityUser LastModifier { get; set; }
 67
 68         #endregion
 69
 70         #region ITree成员
 71
 72         public virtual TIdentityRole Parent { get; set; }
 73
 74         public virtual IList<TIdentityRole> Children { get; set; }
 75
 76         [DoNotNotify, NotMapped]
 77         public virtual int Depth => Parent?.Depth + 1 ?? 0;
 78
 79         [DoNotNotify, NotMapped]
 80         public virtual bool IsRoot => Parent == null;
 81
 82         [DoNotNotify, NotMapped]
 83         public virtual bool IsLeaf => Children?.Count == 0;
 84
 85         [DoNotNotify, NotMapped]
 86         public virtual bool HasChildren => !IsLeaf;
 87
 88         [DoNotNotify, NotMapped]
 89         public virtual string Path => Parent == null ? Id.ToString() : $@"{Parent.Path}/{Id}";
 90
 91         #endregion
 92
 93         #region IPropertyChangeTrackable成员
 94
 95         private static readonly object Locker = new object();
 96         private static readonly Dictionary<Type, string[]> PropertyNamesDictionary = new Dictionary<Type, string[]>();
 97
 98         private readonly BitArray _propertyChangeMask;
 99
100         /// <summary>
101         /// 全局属性变更通知事件处理器
102         /// </summary>
103         public static PropertyChangedEventHandler PublicPropertyChangedEventHandler { get; set; }
104
105         /// <summary>
106         /// 初始化用于跟踪属性变更所需的属性信息
107         /// </summary>
108         protected ApplicationRole()
109         {
110             //判断类型是否已经加入字典
111             //将未加入的类型添加进去(一般为该类对象首次初始化时)
112             var type = this.GetType();
113             if (!PropertyNamesDictionary.ContainsKey(type))
114             {
115                 lock (Locker)
116                 {
117                     if (!PropertyNamesDictionary.ContainsKey(type))
118                     {
119                         PropertyNamesDictionary.Add(type, type.GetProperties()
120                             .OrderBy(property => property.Name)
121                             .Select(property => property.Name).ToArray());
122                     }
123                 }
124             }
125
126             //初始化属性变更掩码
127             _propertyChangeMask = new BitArray(PropertyNamesDictionary[type].Length, false);
128
129             //注册全局属性变更事件处理器
130             if (PublicPropertyChangedEventHandler != null)
131             {
132                 PropertyChanged += PublicPropertyChangedEventHandler;
133             }
134         }
135
136         /// <summary>
137         /// 属性变更事件
138         /// </summary>
139         public event PropertyChangedEventHandler PropertyChanged;
140         public event PropertyChangedExtensionEventHandler PropertyChangedExtension;
141
142         /// <summary>
143         /// 内部属性变更事件处理器
144         /// </summary>
145         /// <param name="propertyName">属性名</param>
146         /// <param name="oldValue">旧值</param>
147         /// <param name="newValue">新值</param>
148         protected virtual void OnPropertyChanged(string propertyName, object oldValue, object newValue)
149         {
150             //Perform property validation
151
152             _propertyChangeMask[Array.IndexOf(PropertyNamesDictionary[this.GetType()], propertyName)] = true;
153
154             PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
155             PropertyChangedExtension?.Invoke(this, new PropertyChangedExtensionEventArgs(propertyName, oldValue, newValue));
156         }
157
158         /// <summary>
159         /// 判断指定的属性或任意属性是否被变更过(<see cref="IPropertyChangeTrackable"/>接口的实现)
160         /// </summary>
161         /// <param name="names">指定要判断的属性名数组,如果为空(null)或空数组则表示判断任意属性。</param>
162         /// <returns>
163         ///    <para>如果指定的<paramref name="names"/>参数有值,当只有参数中指定的属性发生过更改则返回真(True),否则返回假(False);</para>
164         ///    <para>如果指定的<paramref name="names"/>参数为空(null)或空数组,当实体中任意属性发生过更改则返回真(True),否则返回假(False)。</para>
165         ///    </returns>
166         public bool HasChanges(params string[] names)
167         {
168             if (!(names?.Length > 0))
169             {
170                 foreach (bool mask in _propertyChangeMask)
171                 {
172                     if (mask == true)
173                     {
174                         return true;
175                     }
176                 }
177
178                 return false;
179             }
180
181             var type = this.GetType();
182             foreach (var name in names)
183             {
184                 var index = Array.IndexOf(PropertyNamesDictionary[type], name);
185                 if (index >= 0 && _propertyChangeMask[index] == true)
186                 {
187                     return true;
188                 }
189             }
190
191             return false;
192         }
193
194         /// <summary>
195         /// 获取实体中发生过变更的属性集(<see cref="IPropertyChangeTrackable"/>接口的实现)
196         /// </summary>
197         /// <returns>如果实体没有属性发生过变更,则返回空白字典,否则返回被变更过的属性键值对</returns>
198         public IDictionary<string, object> GetChanges()
199         {
200             Dictionary<string, object> changeDictionary = new Dictionary<string, object>();
201             var type = this.GetType();
202             for (int i = 0; i < _propertyChangeMask.Length; i++)
203             {
204                 if (_propertyChangeMask[i] == true)
205                 {
206                     changeDictionary.Add(PropertyNamesDictionary[type][i],
207                         type.GetProperty(PropertyNamesDictionary[type][i])?.GetValue(this));
208                 }
209             }
210
211             return changeDictionary;
212         }
213
214         /// <summary>
215         /// 重置指定的属性或任意属性变更状态(为未变更)(<see cref="IPropertyChangeTrackable"/>接口的实现)
216         /// </summary>
217         /// <param name="names">指定要重置的属性名数组,如果为空(null)或空数组则表示重置所有属性的变更状态(为未变更)</param>
218         public void ResetPropertyChangeStatus(params string[] names)
219         {
220             if (names?.Length > 0)
221             {
222                 var type = this.GetType();
223                 foreach (var name in names)
224                 {
225                     var index = Array.IndexOf(PropertyNamesDictionary[type], name);
226                     if (index >= 0)
227                     {
228                         _propertyChangeMask[index] = false;
229                     }
230                 }
231             }
232             else
233             {
234                 _propertyChangeMask.SetAll(false);
235             }
236         }
237
238         #endregion
239     }

可以看到我在为 IdentityRole 添加接口实现的时候添加的是 IDomainTreeEntity 接口。在这里我把 Role 改成了树形数据类型,也就是说一个角色可以是另一个角色的子角色,构成树状关系。当然如果就当作普通的 Role 来使用也没有任何问题,这个扩展完全不会破坏任何内置功能,没有任何侵入性,按需选用就好,至于能发挥什么作用,完全看脑洞有多大 (●‘?‘●)

然而,这还不是全部,不然就对不起魔改的名号了。现在看见的代码还不是最终形态。因为使用了 PropertyChanged.Fody 这个库,所有的实体都可以向外发送属性变更通知,至于能发挥什么作用,还是看脑洞。

代码最终形态预览(此处使用了 ILSpy 反编译引擎的 Nuget 包,详情见我之前的博客C# 编译器 和 反编译器,你要哪个(歪头)? 我全都要(捏拳)!):

魔改部分还不止这些,但是和我接下来打算介绍的部分存在重叠,所以剩下的部分就和接下来的介绍放在一起了,会新开一篇博客。

各位观众老爷对我的魔改实体类有什么感想欢迎评论交流。可以到下方我的 Github 存储库下载项目运行体验效果。

转载请完整保留以下内容并在显眼位置标注,未经授权删除以下内容进行转载盗用的,保留追究法律责任的权利!

  本文地址:https://www.cnblogs.com/coredx/p/12310010.html

  完整源代码:Github

  里面有各种小东西,这只是其中之一,不嫌弃的话可以Star一下。

原文地址:https://www.cnblogs.com/coredx/p/12310010.html

时间: 2024-07-31 08:52:02

Asp.Net Core Identity 骚断腿的究极魔改实体类的相关文章

ASP.NET Core Identity Hands On(1)——Identity 初次体验

ASP.NET Core Identity是用于构建ASP.NET Core Web应用程序的成员资格系统,包括成员资格.登录和用户数据存储 这是来自于 ASP.NET Core Identity 仓库主页的官方介绍,如果你是个萌新你可能不太理解什么是成员资格,那我来解释一下,成员资格由 membership 直译而来, membership 还有会员资格.会员身份.会员全体等相关含义,我们可以将其简单直接但并非十分恰当的理解为用户管理系统 ASP.NET Core Identity(下文简称I

使用 ASP.NET Core Identity 的 IdentityServer4 授权服务器(二)

在 使用 ASP.NET Core Identity 的 IdentityServer4 授权服务器(1) 中,IdentityServer4 使用的是内存数据,不方便灵活,这次要把 IdentityServer4 的数据也保存到数据库中. 添加 IdentityServer4.EntityFramework IdentityServer4 有两种类型的数据需要保存数据库中.第一是配置数据(资源和客户端).第二个是 IdentityServer 在使用时产生的操作数据(令牌,代码和同意).这些存

在 Ubuntu 16.04 上的 ASP.NET Core 应用开发04:使用 ASP.NET Core Identity 的 IdentityServer4 授权服务器

新建 ASP.NET Core Identity 项目 在新建ASP.NET Core Web 应用程序 窗口中分别选择:ASP.NET Core 2.0,Web应用程序(模型视图控制器)和个人用户账号 项目建立后, 运行方式改为使用控制台运行而不是IISExpress, 以便查看各种debug信息. 打开launchSettings.json: { "profiles": { "IdentityManagerServer": { "commandName

用例子看ASP.NET Core Identity是什么?

原文:用例子看ASP.NET Core Identity是什么? 目录 前言 基于声明的认证(Claims-based Authentication) Claim 在ASP.NET Core Identity中是如何实现的 类ClaimsPrincipal 考察另外一个重要的类ClaimsIdentity 在ASP.NET Core Identity中一同运行 总结 @ 前言 有三个重要的类Claim, ClaimsIdentity, ClaimsPrincipal,我们以一个持有合法证件的学生

Asp.Net Core Identity 完成注册登录

Identity是Asp.Net Core全新的一个用户管理系统,它是一个完善的全面的庞大的框架,提供的功能有: 创建.查询.更改.删除账户信息 验证和授权 密码重置 双重身份认证 支持扩展登录,如微软.Facebook.google.QQ.微信等 提供了一个丰富的API,并且这些API还可以进行大量的扩展 接下来我们先来看下它的简单使用.首先在我们的DbContext中需要继承自IdentityDbContext. public class AppDbContext:IdentityDbCon

使用Asp.Net Core Identity给用户添加及删除角色

基于Asp.Net Core编制一个项目,需要给用户添加及删除角色的功能,于是使用到了Identity中的UserManager. 先后解决了几个问题,终于实现了设想. 1. 环境条件 Asp.Net Core 1.0.1 Microsoft.AspNetCore.Identity.EntityFrameworkCore 1.0.0 2. 给用户添加角色(组)使用到UserManager.AddToRolesAsync(),元数据中对AddToRolesAsync的解释为: // // 摘要:

第16章 使用ASP.NET Core Identity

注意 对于任何先决条件(例如模板),首先要查看概述. IdentityServer旨在提供灵活性,其中一部分允许您为用户及其数据(包括账户密码)使用所需的任何数据库.如果您从新的用户数据库开始,那么ASP.NET Identity是您可以选择的一个选项.本快速入门显示了如何在IdentityServer中使用ASP.NET Identity. 本快速入门使用ASP.NET Identity的方法是为IdentityServer Host创建一个新项目.这个新项目将取代我们在之前的快速入门中构建的

ASP.NET Core MVC 2.x 全面教程_ASP.NET Core MVC 14. ASP.NET Core Identity 入门

默认的身份认证好授权系统 UserManager用来操作用户的类, Singi用来身份认证的 添加AccountController 先声明SignInManager和UserManager这两个服务 快捷键Ctrl+. 两个都需要分别进行Ctrl+.快速的生成 创建登陆的Action Login 建立View 创建LoginViewModel 主要是用户名和密码两个字段 登陆的逻辑 注册的逻辑 退出的逻辑 创建regiser的视图页面 在_Lauout里面添加了注册和登陆的链接 点击注册发现报

开源DDD设计模式框架YMNNetCoreFrameWork第二篇-增加ASp.net core Identity身份认证,JWT身份认证

1.框架增加Identity注册功能 2.框架增加identity登录以后获取JWTtoken 3.请求接口通过token请求,增加验证特性 源代码地址:https://github.com/topgunymn/YMNNetCoreFrameWork JWTtoken生成代码: private string CreateAccessToken(IEnumerable<Claim> claims, TimeSpan? expiration = null) { var now = DateTime