站长素材网,学设计网站推荐,哈尔滨优化seo外包公司,杭州做网站公司有哪些一、AbpSession是Session吗#xff1f;
1、首先来看看它们分别对应的类型是什么#xff1f;
查看源码发现Session是定义在Controller中的类型为HttpSessionStateBase的属性。 public HttpSessionStateBase Session { get; set; }
再来看看AbpSession是何须类也#xff0c…一、AbpSession是Session吗
1、首先来看看它们分别对应的类型是什么
查看源码发现Session是定义在Controller中的类型为HttpSessionStateBase的属性。 public HttpSessionStateBase Session { get; set; }
再来看看AbpSession是何须类也咱们定位到AbpController中看一看。 public IAbpSession AbpSession { get; set; }
好吧原来AbpSession是IAbpSession类型啊。但这就可以断定AbpSession不是Session吗 未必吧如果IAbpsession的具体实现中还是依赖Session也不一定哦如果是这样那AbpSession可以算作Session的扩展也可以说是Session。 咱还是找找IAbpsession的具体实现一探究竟吧。 Abp中对IAbpsession有两个实现方式一种是NullAbpSessionNullAbpSession是空对象设计模式用于属性注入时在构造函数中对其初始化。 另一种是ClaimsAbpSession咱们来一探究竟。
2、一探究竟ClaimsAbpSession
以下代码是ClaimsAbpSession的节选
/// summary
/// Implements see crefIAbpSession/ to get session properties from claims of see crefThread.CurrentPrincipal/.
/// /summary
public class ClaimsAbpSession : IAbpSession, ISingletonDependency
{public virtual long? UserId{get{var userIdClaim PrincipalAccessor.Principal?.Claims.FirstOrDefault(c c.Type ClaimTypes.NameIdentifier);if (string.IsNullOrEmpty(userIdClaim?.Value)){return null;}long userId;if (!long.TryParse(userIdClaim.Value, out userId)){return null;}return userId;}}public IPrincipalAccessor PrincipalAccessor { get; set; }public ClaimsAbpSession(IMultiTenancyConfig multiTenancy){MultiTenancy multiTenancy;PrincipalAccessor DefaultPrincipalAccessor.Instance;}
}
其中IPrincipalAccessor又是什么鬼从构造函数来看DefaultPrincipalAccessor应该是个单例模式。
public class DefaultPrincipalAccessor : IPrincipalAccessor, ISingletonDependency
{public virtual ClaimsPrincipal Principal Thread.CurrentPrincipal as ClaimsPrincipal;public static DefaultPrincipalAccessor Instance new DefaultPrincipalAccessor();
}
其中public static DefaultPrincipalAccessor Instance new DefaultPrincipalAccessor();是属性表达式写法相当于
public static DefaultPrincipalAccessor Instance
{ get { new DefaultPrincipalAccessor();}
}
所以并非是单例模式长了个记性并不是定义了Instance属性的就是单例
将上面两部分代码一中和AbpSession中的UserId不就是这样获得的 ((ClaimsPrincipal)Thread.CurrentPrincipal).Claims.FirstOrDefault(c c.Type ClaimTypes.NameIdentifier);
好了一切一目了然了AbpSession最终依赖的是ClaimsPrincipal并不是Session。
所以AbpSession不是Session 所以AbpSession不是Session 所以AbpSession不是Session
那ClaimsPrincipal又是什么鬼我就喜欢你这打破砂锅问到底的劲且听我娓娓道来。
二、Identity身份认证
1、Cliam身份信息
拿身份证举例其中包括姓名奥巴马、性别男、民族xx、出生xx、住址xx、公民省份号码xxx这些键值对都是身份信息。其中姓名、性别、民族、出生、住址、公民省份号码这些是身份信息类别ClaimsType微软已经给我们预定义了一系列的身份信息类别其中包括Email、Gender、Phone等等。 2、ClaimsIdentity身份证
有了身份信息一组装不就成了身份证。 看下ClaimsIdentity的简要代码
public class ClaimsIdentity: IIdentity
{public virtual IEnumerableClaim Claims{get { //省略其他代码 }}//名字这么重要当然不能让别人随便改啊所以我不许 set除了我儿子跟我姓所以是 virtual 的public virtual string Name { get; }//这是我的证件类型也很重要同样不许 setpublic virtual string AuthenticationType { get; }public virtual void AddClaim(Claim claim);public virtual void RemoveClaim(Claim claim);public virtual void FindClaim(Claim claim);
}
可以看到ClaimsIdentity维护了一个Claim枚举列表。 其中AuthenticationType从字面意思理解是验证类型。什么意思呢比如我们拿身份证去政府部门办理业务时有时需要持本人身份证但有时候需要身份证复印件即可。
3、ClaimsPrincipal 证件所有者
我们用身份信息构造了一个身份证这个身份证肯定是属于具体的某个人吧。 所以ClaimsPrincipal就是用来维护一堆证件的。 因为现实生活中也是这样我们有身份证、银行卡、社保卡等一系列证件。 那咱们就来看.net中是怎样实现的
//核心代码部分
public class ClaimsPrincipal :IPrincipal
{//把拥有的证件都给当事人public ClaimsPrincipal(IEnumerableClaimsIdentity identities){}//当事人的主身份呢public virtual IIdentity Identity { get; }public virtual IEnumerableClaimsIdentity Identities { get; }public virtual void AddIdentity(ClaimsIdentity identity);//为什么没有RemoveIdentity 留给大家思考吧
}
了解了这些概念我们再来看看Identity的简要登陆流程 从这张图来看我们登陆的时候提供一些身份信息Claim用户名/密码然后Identity中间件根据这些身份信息构造出一张身份证ClaimsIdentity然后把身份证交给ClaimsPrincipal证件所有者保管。
三、捋一捋Abp中的登陆流程
定位到AccountController关注下以下代码
[HttpPost]
[DisableAuditing]
public async TaskJsonResult Login(LoginViewModel loginModel, string returnUrl , string returnUrlHash )
{CheckModelState();var loginResult await GetLoginResultAsync(loginModel.UsernameOrEmailAddress,loginModel.Password,loginModel.TenancyName);await SignInAsync(loginResult.User, loginResult.Identity, loginModel.RememberMe);if (string.IsNullOrWhiteSpace(returnUrl)){returnUrl Request.ApplicationPath;}if (!string.IsNullOrWhiteSpace(returnUrlHash)){returnUrl returnUrl returnUrlHash;}return Json(new AjaxResponse { TargetUrl returnUrl });
}private async TaskAbpLoginResultTenant, User GetLoginResultAsync(string usernameOrEmailAddress, string password, string tenancyName)
{var loginResult await _logInManager.LoginAsync(usernameOrEmailAddress, password, tenancyName);switch (loginResult.Result){case AbpLoginResultType.Success:return loginResult;default:throw CreateExceptionForFailedLoginAttempt(loginResult.Result, usernameOrEmailAddress, tenancyName);}
}private async Task SignInAsync(User user, ClaimsIdentity identity null, bool rememberMe false)
{if (identity null){identity await _userManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);}AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent rememberMe }, identity);
}
分析发现主要包括以下几个步骤 1、 GetLoginResultAsync -- loginManager.LoginAsync -- userManager.CreateIdentityAsync不要以为调用了LoginAsync就以为是登录其实这是伪登录。主要根据用户名密码去核对用户信息构造User对象返回然后再根据User对象的身份信息去构造身份证CliamsIdentity。 2、SignInAsync -- AuthenticationManager.SignOut --AuthenticationManager.SignIn AuthenticationManager认证管理员负责真正的登入登出。SignIn的时候将第一步构造的身份证CliamsIdentity交给证件所有者ClaimsPrincipal。
是不是明白该怎么扩展AbpSession了 关键是往身份证CliamsIdentity中添加身份信息Cliam啊 其实去github上Abp官网搜issue发现土耳其大牛也是给的这种扩展思路详参此链。
四、开始扩展AbpSession第一种方式推荐
上一节已经理清了思路这一节咱们就撸起袖子扩展吧。 现在假设我们需要扩展一个Email属性
1、登录前添加Cliam身份信息
定位到AccountController修改SignInAsync方法在调用AuthenticationManager.SignIn之前添加下面代码 identity.AddClaim(new Claim(ClaimTypes.Email, user.EmailAddress)); 2、定义IAbpSession扩展类获取扩展属性
既然只要我们在登录的时候通过在身份信息中添加要扩展的属性我们就可以通过ClaimsPrincipal中获取扩展的属性。 所以我们可以通过对IAbpSession进行扩展通过扩展方法从CliamsPrincipal中获取扩展属性。
所以我们需要在领域层也就是.Core结尾的项目中对IAbpSession进行扩展。定位到.Core结尾的项目中添加Extensions文件夹添加扩展类AbpSessionExtension2
namespace LearningMpaAbp.Extensions
{/// summary/// 通过扩展方法来对AbpSession进行扩展/// /summarypublic static class AbpSessionExtension2{public static string GetUserEmail(this IAbpSession session){return GetClaimValue(ClaimTypes.Email);}private static string GetClaimValue( string claimType){var claimsPrincipal DefaultPrincipalAccessor.Instance.Principal;var claim claimsPrincipal?.Claims.FirstOrDefault(c c.Type claimType);if (string.IsNullOrEmpty(claim?.Value))return null;return claim.Value;}}
}
通过扩展类我们不需要做其他额外的更改即可通过ApplicationService, AbpController 和 AbpApiController 这3个基类已经注入的AbpSession属性调用GetUserEmail()来获取扩展的Email属性。
这种方式时最简单的方式推荐此种方法
五、开始扩展AbpSession第二种方式
ApplicationService, AbpController 和 AbpApiController 这3个基类已经注入了AbpSession属性。 所以我们需要在领域层也就是.Core结尾的项目中对AbpSession进行扩展。 现在假设我们需要扩展一个Email属性。
1、扩展IAbpSession
定位到.Core结尾的项目中添加Extensions文件夹然后添加IAbpSessionExtension接口继承自IAbpSession
namespace LearningMpaAbp.Extensions
{public interface IAbpSessionExtension : IAbpSession{string Email { get; }}
}
2、实现IAbpSessionExtension
添加AbpSessionExtension类继承自ClaimsAbpSession并实现IAbpSessionExtension接口。
namespace LearningMpaAbp.Extensions
{public class AbpSessionExtension : ClaimsAbpSession, IAbpSessionExtension{public AbpSessionExtension(IMultiTenancyConfig multiTenancy) : base(multiTenancy){}public string Email GetClaimValue(ClaimTypes.Email);private string GetClaimValue(string claimType){var claimsPrincipal PrincipalAccessor.Principal;var claim claimsPrincipal?.Claims.FirstOrDefault(c c.Type claimType);if (string.IsNullOrEmpty(claim?.Value))return null;return claim.Value;}}
}
3、替换掉注入的AbpSession属性
先来替换掉AbpController中注入的AbpSession 定位到.Web\Controllers\xxxxControllerBase.cs使用属性注入IAbpSessionExtension。添加以下代码
//隐藏父类的AbpSession
public new IAbpSessionExtension AbpSession { get; set; }
再来替换掉ApplicationService中注入的AbpSession 定位到.Application\xxxxAppServiceBase.cs。使用属性注入IAbpSessionExtension同样添加以下代码
//隐藏父类的AbpSession
public new IAbpSessionExtension AbpSession { get; set; }
至于AbpApiController要不要替换AbpSession就视情况而定了如果你使用的是Abp提供的动态WebApi技术就不需要替换了因为毕竟最终调用的是应用服务层的Api。如果WebApi是自己代码实现的那就仿照上面自行替换吧就不罗嗦了。
很显然这种方式教第一种方式要麻烦许多。。。
4、无图无真相 总结
本文首先对AbpSession一探真面目了解到AbpSession不是Session 然后对Identity身份认证流程就行简要剖析发现AbpSession是依赖于ClaimsPrincipal从而确定扩展AbpSession的思路关键是往身份证CliamsIdentity中添加身份信息Cliam啊 最终提供了两种扩展思路 其中推荐通过对IAbpSession进行扩展通过扩展方法从CliamsPrincipal中获取扩展属性。 本文参考了以下博文在此再次感谢它们的精彩分享 ASP.NET Core 之 Identity 入门一--Savorboard ASP.NET Core 之 Identity 入门二--Savorboard ASP.NET Core 之 Identity 入门三--Savorboard Asp.net Boilerplate之AbpSession扩展--kid1412 基于DDD的.NET开发框架 - ABP Session实现--Joye.Net 阅罢此文如果您觉得本文不错并有所收获请【打赏】或【推荐】也可【评论】留下您的问题或建议与我交流。 你的支持是我不断创作和分享的不竭动力