一.AbpSession的认识

在ABP中提供了IAbpSession的接口用来获取用户和租户的信息,没有使用Asp.Net中的Session,那么AbpSession到底和Session有没有关系?具体是怎么实现的呢?

在ABP的源码中共有两个类具体实现了IAbpSession接口:NullAbpSession和ClaimAbpSession,其中NullAbpSession实现了空对象设计模式,那么主要的代码就是在这个ClaimAbpSession中

从上面的代码中我们可以看出我们的用户ID是通过PrincipalAcessor.Principal获取到的,那么这又是一个什么东西呢?

其中ClaimsPricipal是微软提供的用于登陆验证的的一个类。从上面的代码中,我们终于了解到其实AbpSession和Session没有任何关系的。我们的AbpSession就是从这个类里面获取的相应的信息(用户ID,租户ID,模拟用户Id,模拟租户ID),那么问题来了,这个ClaimsPricipal到底又是一个什么东西呢?

二.了解Identity

1.为什么要使用Asp.net Identity,它有什么优势呢?

1).作为一种用户角色管理的组件,支持Asp.net MVC、Asp.net Core 、WebApi等微软的框架,可以很方便的集成。其实我们新建的MVC项目中,已经把Identity的相关组件库引用进去了。

2).支持持久化,可以很方便的对接EF和EFCore

3).可以很容易的创建角色和用户,管理方便

4).可以很方方便的和第三方用户登陆对接。

2.identity中有三个比较重要的对象。

Claim(证件信息,重点是信息)

简单来说这个对象就是一个键值对,存放信息用的

上面的type表示的信息的类型,在identity中其实已经提供了一些经常使用的类型的类ClaimTypes

ClaimIdentity(证件)

这个东西存放的就是我们Claim的集合,通过很多的Claim信息,我们就可以拼装成我们的证件ClaimIdentity,比如我们的身份证,需要提供性别,姓名,出生年月,家庭地址等Claim信息,然后就组装成了我们的身份证(ClaimIdentity)

其中AuthenticationType就是证件的类型,我们的证件信息组成的证件可以存在多种展现形式,拿我们的身份证来说,有实体证件和电子复印件。还有我们的车票,可以是电子票,也可以是实体票

ClaimsPrincipal(证件持有者)

这个类中存放了很多的证件ClaimIdentity,它就像一个人,同时可以持有身份证,车票,三好学生证等证件

3.Asp.net Identity的是实例应用

其实在我们创建我们的MVC项目的时候,在菜单栏中就存在相应的选项,是否使用身份验证。

接下来我将通过AccountController(账号登陆注册控制器)详细了解下一Identity的机制,在Identity中存在三个重要的Manager对象

1.UserMananger

UserMananger对象用来处理创建用户等逻辑

2.SignManager

SignManager对象用来对用户的登陆和登出的逻辑进行处理

3.RoleManager

RoleManager对象用来对用用户角色相关逻辑进行处理。

 三.Abp中Claim的使用

从上面的代码中,我们可以看出在_logInManager.LoginAsync这个方法中,会将我们的Claim信息构造为证件ClaimIdentity,这个可以在Abp源码中看到。那么我们的ClaimIdentiy这些证件信息是如何添加到证件持有人ClaimPricipal中的呢?只有将信息存放在ClaimPricipal中,才会有最上面,从ClaimPricipal中获取我们的用户信息的操作。其实我们猜一猜可以知道。这个操作肯定是在登陆的时候,信息存放在ClaimPricipal中的。其实_logInManager.LoginAsync也实现了。但是通过源码中我们发现,不仅仅这个方法中实现了往ClaimPricipal中添加信息的,在后面的SignManager.SignAsync中也实现了,这个将是我们后面扩展AbpSession的关键,具体的源码将在AbpSession扩展中给出。

四.AbpSession的扩展

我们已经知道AbpSession并不是Session,我们的登陆信息没有使用Session的方式存储,而是使用ClaimPrincipal的方式存放的,那么我们需要额外的存放一些我们的信息在我们的Abp系统中,需要怎么做呢?其实很简单啊,不就是我向ClaimPricipal中的添加ClaiIdentity嘛。首先看一下我们Account中代码

答案是可以的,这个我们可以从Abp的源码中找到答案。

在扩展前,我们需要将我们自定义的Claim信息添加到ClaimIdentity中去,修改AccountController的Login方法

第一种扩展思路:通过对AbpSession添加扩展方法的方式,获取到自定义的Claim

在Core层添加我们的扩展类
public static class AbpSessionExtension
{
public static string GetName(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;
}
} 在Controller中调用
public class HomeController : StudyABPProjectControllerBase
{ public ActionResult Index()
{
var name = AbpSession.GetName();
return Content(name);
}
}

理想是美好的,现实是残酷的,在abp.core项目中,无法获取到我们自定义的信息,因为DefaulPricinpalAccessor.Instance,就是通过Thread.CurentPrincipal获取的当前的证件拥有者,但是在Core项目中,这个对象始终为null,所以导致无法获取到principal。

第二种扩展思路:直接修改原有AbpSession,使用我们自己定义的AbpSession覆盖原来的,然后在我们自定义的AbpSession中添加我们自定义的属性

1.首先创建我们的MyAbpSession和IMyAbpSession

  public class MyAbpSession : ClaimsAbpSession, IMyAbpSession
{
public MyAbpSession(IPrincipalAccessor principalAccessor, IMultiTenancyConfig multiTenancy, ITenantResolver tenantResolver, IAmbientScopeProvider<SessionOverride> sessionOverrideScopeProvider) : base(principalAccessor, multiTenancy, tenantResolver, sessionOverrideScopeProvider)
{
} private string GetClaimValue(string claimType)
{ var claimsPrincipal = this.PrincipalAccessor.Principal; var claim = claimsPrincipal?.Claims.FirstOrDefault(c => c.Type == claimType);
if (string.IsNullOrEmpty(claim?.Value))
return null; return claim.Value;
}
public string MyName => GetClaimValue("MyName");
} public interface IMyAbpSession:IAbpSession
{
string MyName { get; }
}

2.在UI层和Application层覆盖原来的AbpSession

  public abstract class StudyABPProjectControllerBase: AbpController
{
public new IMyAbpSession AbpSession { get; set; }
protected StudyABPProjectControllerBase()
{
LocalizationSourceName = StudyABPProjectConsts.LocalizationSourceName;
} protected void CheckErrors(IdentityResult identityResult)
{
identityResult.CheckErrors(LocalizationManager);
}
}

直接运行我们代码

OK,我们的AbpSession通过重写原来的AbpSession正确获取到了我们添加的数据。

会话管理之AbpSession的更多相关文章

  1. 3种web会话管理的方式

    http是无状态的,一次请求结束,连接断开,下次服务器再收到请求,它就不知道这个请求是哪个用户发过来的.当然它知道是哪个客户端地址发过来的,但是对于我们的应用来说,我们是靠用户来管理,而不是靠客户端. ...

  2. Nodejs之MEAN栈开发(八)---- 用户认证与会话管理详解

    用户认证与会话管理基本上是每个网站必备的一个功能.在Asp.net下做的比较多,大体的思路都是先根据用户提供的用户名和密码到数据库找到用户信息,然后校验,校验成功之后记住用户的姓名和相关信息,这个信息 ...

  3. JWT实现token-based会话管理

    上文<3种web会话管理的方式>介绍了3种会话管理的方式,其中token-based的方式有必要从实现层面了解一下.本文主要介绍这方面的内容.上文提到token-based的实现目前有一个 ...

  4. java的会话管理:Cookie和Session

    java的会话管理:Cookie和Session 1.什么是会话 此处的是指客户端(浏览器)和服务端之间的数据传输.例如用户登录,购物车等 会话管理就是管理浏览器客户端和服务端之间会话过程产生的会话数 ...

  5. PHP会话管理:cookie和session

    PHP会话管理1.cookie数据存储在浏览器端方便与JavaScript交换数据方便获取用户信息风险-浏览器可能会禁用cookie替代方案-URL参数 2.session数据存储在服务器高效.安全. ...

  6. Centos screen远程会话管理命令

    screen参数 -A 将所有的视窗都调整为目前终端机的大小. -d<作业名称> 将指定的screen作业离线. -h<行数> 指定视窗的缓冲区行数. -m 即使目前已在作业中 ...

  7. Spring in action - 会话管理

    传统的会话管理是用一个session表保存会话信息,每次请求时读取.写入该表. public function read($sessID) { $hander = is_array($this-> ...

  8. OWASP WEB会话管理备忘单 阅读笔记

    https://www.owasp.org/index.php/Session_Management_Cheat_Sheet#Session_ID_Properties 会话简介 HTTP是一种无状态 ...

  9. 3种 web 会话管理的方式

    转自:http://www.yidianzixun.com/n/0F1GYAsQ?s=8&appid=xiaomi&ver=3.7.8&utk=4lxc4q7c&fro ...

随机推荐

  1. TF_Server gRPC failed, call return code:8:Received message larger than max (45129801 vs. 4194304)

    tensorflow_serving 遇到错误:gRPC failed, call return code:8:Received message larger than max (45129801 v ...

  2. wine qq 2013 for linux deb包 Ubuntu 64位兼容

    2013-08-08     Wine 1.6,如果您想体验下该版本的wine,目前可以通过ppa进行安装:   sudo add-apt-repository ppa:ubuntu-wine/ppa ...

  3. 【SqlServer】SqlServer的常规操作

    创建一张新表,不负责任何数据(该表不会有原来表的主键.索引等等) select * into NewTable from OldTable where 1<>1; 创建一张新表,并且复制旧 ...

  4. MySQL 管理之道读书总结

    最近读了<MySQL 管理之道>一书,做了以下总结,希望对大家有所帮助.在这里非常感谢作者的辛勤付出. 影响 MySQL 性能的因素:     影响 MySQL InnoDB 引擎性能的最 ...

  5. 经典的sql语句,将返回结果合并为一个字符串

    declare @ts varchar(999) select @ts=isnull(@ts+',','')+name from sysobjects where xtype='U' select @ ...

  6. 译:6.RabbitMQ Java Client 之 Remote procedure call (RPC,远程过程调用)

    在  译:2. RabbitMQ 之Work Queues (工作队列)  我们学习了如何使用工作队列在多个工作人员之间分配耗时的任务. 但是如果我们需要在远程计算机上运行一个函数并等待结果呢?嗯,这 ...

  7. Fluent动网格【7】:网格节点运动

    在动网格中,对于那些既包含了运动也包含了变形的区域,可以通过UDF来指定区域中每一个节点的位置.这给了用户最大的自由度来指定网格的运动.在其他的动网格技术中(如重叠网格)则很难做到这一点.定义网格节点 ...

  8. GNU make使用(二)

    [时间:2017-06] [状态:Open] [关键词:makefile,gcc,编译,shell命令,目标文件] 0 引言及目标 之前使用Makefile都是把源文件和目标文件放到同一个目录编译.近 ...

  9. Android 录音和播放

    今天工作上需要做一个一边录音一边播放的功能,大致原因是有一个外部设备输入音频到我们机器,然后我们机器需要马上把音频播放出来.所以了解了一些有关录音和播放的知识.接到这个任务的第一反应就是看看Andro ...

  10. vs2013 error LNK2005 已经在***.obj中定义

    错误解决办法: 方法一: 中文 项目--属性 ---连接器---输入                               附加依赖项    空格Nafxcwd.lib Libcmtd.lib ...