ABP+AdminLTE+Bootstrap Table权限管理系统第八节--ABP错误机制及AbpSession相关

  返回总目录:ABP+AdminLTE+Bootstrap Table权限管理系统一期

     上一节我们讲到登录逻辑,我做的登录逻辑很简单的,我们来看一下abp module-zero里面的登录代码.

 #region Login / Logoutpublic ActionResult Login(string returnUrl = ""){if (string.IsNullOrWhiteSpace(returnUrl)){returnUrl = Request.ApplicationPath;}return View(new LoginFormViewModel{ReturnUrl = returnUrl,IsMultiTenancyEnabled = _multiTenancyConfig.IsEnabled});}[HttpPost]public async Task<JsonResult> 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 Task<AbpLoginResult<Tenant, User>> GetLoginResultAsync(string usernameOrEmailAddress, string password, string tenancyName){try{var loginResult = await _logInManager.LoginAsync(usernameOrEmailAddress, password, tenancyName);switch (loginResult.Result){case AbpLoginResultType.Success:return loginResult;default:throw CreateExceptionForFailedLoginAttempt(loginResult.Result, usernameOrEmailAddress, tenancyName);}}catch (Exception e){Console.WriteLine(e);throw;}}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);}private Exception CreateExceptionForFailedLoginAttempt(AbpLoginResultType result, string usernameOrEmailAddress, string tenancyName){switch (result){case AbpLoginResultType.Success:return new ApplicationException("Don't call this method with a success result!");case AbpLoginResultType.InvalidUserNameOrEmailAddress:case AbpLoginResultType.InvalidPassword:return new UserFriendlyException(L("LoginFailed"), L("InvalidUserNameOrPassword"));case AbpLoginResultType.InvalidTenancyName:return new UserFriendlyException(L("LoginFailed"), L("ThereIsNoTenantDefinedWithName{0}", tenancyName));case AbpLoginResultType.TenantIsNotActive:return new UserFriendlyException(L("LoginFailed"), L("TenantIsNotActive", tenancyName));case AbpLoginResultType.UserIsNotActive:return new UserFriendlyException(L("LoginFailed"), L("UserIsNotActiveAndCanNotLogin", usernameOrEmailAddress));case AbpLoginResultType.UserEmailIsNotConfirmed:return new UserFriendlyException(L("LoginFailed"), "UserEmailIsNotConfirmedAndCanNotLogin");case AbpLoginResultType.LockedOut:return new UserFriendlyException(L("LoginFailed"), L("UserLockedOutMessage"));default: //Can not fall to default actually. But other result types can be added in the future and we may forget to handle itLogger.Warn("Unhandled login fail reason: " + result);return new UserFriendlyException(L("LoginFailed"));}}public ActionResult Logout(){AuthenticationManager.SignOut();return RedirectToAction("Login");}#endregion

由于abp涉及到租户和身份验证的问题,所以登录有点繁琐.分析发现主要包括以下几个步骤:

1、 GetLoginResultAsync --> loginManager.LoginAsync --> userManager.CreateIdentityAsync:不要以为调用了LoginAsync就以为是登录,其实这是伪登录。主要根据用户名密码去核对用户信息,构造User对象返回,然后再根据User对象的身份信息去构造身份证(CliamsIdentity)。
2、SignInAsync --> AuthenticationManager.SignOut
-->AuthenticationManager.SignIn

AuthenticationManager(认证管理员),负责真正的登入登出。SignIn的时候将第一步构造的身份证(CliamsIdentity)交给证件所有者(ClaimsPrincipal)。   
登录完成之后,我们通常会有一个记住用户名密码的功能,有人就会想到abp中的AbpSession.单其实AbpSession不是单纯意义上的Session,比如AbpSession里面的Userid就是通过以下方式获得的.
((ClaimsPrincipal)Thread.CurrentPrincipal).Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier);

       需要获取会话信息则必须实现IAbpSession接口。虽然你可以用自己的方式去实现它(IAbpSession),但是它在module-zero项目中已经有了完整的实现。IAbpSession包含还有其他信息.

 //// 摘要://     Defines some session information that can be useful for applications.public interface IAbpSession{//// 摘要://     TenantId of the impersonator. This is filled if a user with Abp.Runtime.Session.IAbpSession.ImpersonatorUserId//     performing actions behalf of the Abp.Runtime.Session.IAbpSession.UserId.int? ImpersonatorTenantId { get; }//// 摘要://     UserId of the impersonator. This is filled if a user is performing actions behalf//     of the Abp.Runtime.Session.IAbpSession.UserId.long? ImpersonatorUserId { get; }//// 摘要://     Gets current multi-tenancy side.MultiTenancySides MultiTenancySide { get; }//// 摘要://     Gets current TenantId or null. This TenantId should be the TenantId of the Abp.Runtime.Session.IAbpSession.UserId.//     It can be null if given Abp.Runtime.Session.IAbpSession.UserId is a host user//     or no user logged in.int? TenantId { get; }//// 摘要://     Gets current UserId or null. It can be null if no user logged in.long? UserId { get; }//// 摘要://     Used to change Abp.Runtime.Session.IAbpSession.TenantId and Abp.Runtime.Session.IAbpSession.UserId//     for a limited scope.//// 参数://   tenantId:////   userId:IDisposable Use(int? tenantId, long? userId);

             

AbpSession定义的一些关键属性:

1.UserId: 当前用户的标识ID,如果没有当前用户则为null.如果需要授权访问则它不可能为空。

2.TenantId: 当前租户的标识ID,如果没有当前租户则为null。

3.MultiTenancySide: 可能是Host或Tenant。

         UserId和TenantId是可以为null的。当然也提供了不为空时获取数据的 GetUserId()和GetTenantId() 方法 。当你确定有当前用户时,你可以使用GetUserId()方法。如果当前用户为空,使用该方法则会抛出一个异常。GetTenantId()的使用方式和GetUserId()类似。

            IAbpSession通常是以属性注入的方式存在于需要它的类中,不需要获取会话信息的类中则不需要它。如果我们使用属性注入方式,我们可以用 
NullAbpSession.Instance作为默认值来初始化它(IAbpSession)

    public IAbpSession AbpSession { get; set; }private readonly IUserService _iUsersService;public AccountController(IUserService iUsersService){_iUsersService = iUsersService;AbpSession = NullAbpSession.Instance;}// GET: Accountpublic ActionResult Index(){var currentUserId = AbpSession.UserId;return View(); }

          由于授权是应用层的任务,因此我们应该在应用层和应用层的上一层使用IAbpSession(我们不在领域层使用IAbpSession是很正常的)。

ApplicationServiceAbpController 和 AbpApiController 这3个基类已经注入了AbpSession属性,因此在Application Service的实例方法中,能直接使用AbpSession属性。

           ABP框架中的AbpSession, 并没有使用到System.Web.HttpSessionStateBase, 而是自己定义了一个Abp.Runtime.Session.IAbpSession接口, 并在Zero模块中通过AspNet.Identity组件实现了AbpSession对象的存值、取值。 所以即使Web服务重启,也不会丢失Session状态。在我们自己的项目中, Session对象只有UserId、TenantId、MultiTenancySide这几个属性是不够用的,可以自己扩充了几个属性和方法,使用起来非常方便。

      首先我们定义IAbpSession扩展类获取扩展属性,通过扩展类,我们不需要做其他额外的更改,即可通过ApplicationService, AbpController 和 AbpApiController 这3个基类已经注入的AbpSession属性调用GetUserName()来获取扩展的Name属性。

 接口代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace JCmsErp.AbpSessionExtension
{public interface IAbpSessionExtension{string UserName { get; }}
}

实现代码:

using Abp.Configuration.Startup;
using Abp.MultiTenancy;
using Abp.Runtime;
using Abp.Runtime.Session;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;namespace JCmsErp.AbpSessionExtension
{public class AbpSessionExtension : ClaimsAbpSession, IAbpSessionExtension{public AbpSessionExtension(IPrincipalAccessor principalAccessor, IMultiTenancyConfig multiTenancy, ITenantResolver tenantResolver, IAmbientScopeProvider<SessionOverride> sessionOverrideScopeProvider): base(principalAccessor, multiTenancy, tenantResolver, sessionOverrideScopeProvider){}public string UserName => GetUserName(ClaimTypes.Name);private string GetUserName(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;}}
}

 

       然后在登录逻辑中加入以下代码:

  //添加身份信息,以便在AbpSession中使用
identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName));

就这样,我们在ApplicationService, AbpController 和 AbpApiController任何地方注入IAbpSession,然后AbpSession.Name就能获取到我们登录时候添加的信息.

       二,abp的错误机制

          如果登录过程中出错怎么办,报错了ABP怎么反应,我们来看一下abp的错误机制.在web应用中,异常通常在MVC Controller actions和Web API Controller actions中处理。当异常发生时,应用程序的用户以某种方式被告知错误的相关信息及原因。果错误在正常的HTTP请求时发生,将会显示一个异常页。如果在AJAX请求中发生错误,服务器发送错误信息到客户端,然后客户端处理错误并显示给用户。在所有的Web请求中处理异常是件乏味且重复的工作。ABP自动化完成异常处理,几乎从不需要显示的处理任何异常。ABP处理所有的异常、记录异常并返回合适、格式化的响应到客户端。在客户端处理这些响应并将错误信息显示给用户。

     异常显示,首先我们在ActionResult 随便添加一个异常信息,调试一下看一下结果

   

   public ActionResult Index(){// return View();throw new Exception("登录密码错误或用户不存在或用户被禁用。");}

         当然,这个异常可能由另一个方法抛出,而这个方法的调用在这个action里。ABP处理这个异常、记录它并显示'Error.cshtml'视图。你可以自定义这个视图来显示错误。一个示例错误视图(在ABP模板中的默认错误视图):

 

 

BP对用户隐藏了异常的细节并显示了一个标准(本地化的)的错误信息,除非你显示的抛出一个UserFriendlyException,UserFriendlyException UserFriendlyException是一个特殊类型的异常,它直接显示给用户。参见下面的示例:

    // GET: Accountpublic ActionResult Index(){// return View();throw new Abp.UI.UserFriendlyException("登录密码错误或用户不存在或用户被禁用。");}

浏览器结果:

 

 

 

所以,如果你想显示一个特定的错误信息给用户,那就抛出一个UserFriedlyException(或者一个继承自这个类的异常)。

      当然如果是ajax请求里面出错,message API处理JSON对象并显示错误信息给用户。前端应该有相应的错误处理.

  返回总目录:ABP+AdminLTE+Bootstrap Table权限管理系统一期

转载于:https://www.cnblogs.com/anyushengcms/p/7261815.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/400243.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JQuery DataTables Editor---只修改页面内容

https://www.cnblogs.com/zjf1987/p/Editor.html

关于JAVA_HOME, CLASSPATH和PATH的设置

http://bbs.csdn.net/topics/120079565 1、PATH&#xff0c;这个是给WINDOWS操作系统用的&#xff0c;告诉命令行里&#xff0c;执行的命令行工具在那里&#xff0c;比如java,javac这都是命令行工具,你在运行里随便敲一个命令&#xff0c;操作系统怎么就知道你这个命令对应的程…

P2327 [SCOI2005]扫雷

题目描述 输入输出格式 输入格式&#xff1a; 第一行为N&#xff0c;第二行有N个数&#xff0c;依次为第二列的格子中的数。&#xff08;1< N < 10000&#xff09; 输出格式&#xff1a; 一个数&#xff0c;即第一列中雷的摆放方案数。 输入输出样例 输入样例#1&#xff…

天津海运[600751]股票

2019独角兽企业重金招聘Python工程师标准>>> 天津海运[600751]股票 转载于:https://my.oschina.net/chworld/blog/425583

【RK3399Pro学习笔记】十六、ROS中的常用可视化工具

目录测试rqt_consolerqt_graphrqt_plotrqt_image_viewrqtrvizgazebo平台&#xff1a;华硕 Thinker Edge R 瑞芯微 RK3399Pro 固件版本&#xff1a;Tinker_Edge_R-Debian-Stretch-V1.0.4-20200615 记录自【古月居】古月ROS入门21讲 | 一学就会的ROS机器人入门教程 —— 古月居G…

datatables 基本增删改查(php)

http://www.datatables.club/example/user_share/basic_curd.html

基于leveldb,levigo做二次开发

Leveldb是一个C库&#xff0c;它有提供标准的C接口&#xff0c;头文件在include/leveldb/c.h中 levigo是leveldb 的一个go wrapper,它主要基于Leveldb中inlude/leveldb/c.h提供的方法做二次开发 开发过程&#xff0c;以添加一个简单的计算功能为例&#xff1a; 修改leveldb源码…

Cocos2d-x 3.2:通过ClippingNode实现一个功能完善的跑马灯公告(1)

Cocos2d-x 3.2&#xff1a;通过ClippingNode实现一个功能完善的跑马灯公告&#xff08;1&#xff09; 本文转载至深入理解Cocos2d-x 3.x&#xff1a;一步一步通过ClippingNode实现一个功能完善的跑马灯公告&#xff08;1&#xff09; 这篇文章主要是通过一步一步实现一个功能完…

option columns.render 渲染列(1) 添加checkbox

http://www.datatables.club/manual/daily/2016/04/25/option-columns-render1.html

【STC15库函数上手笔记】1、建立工程

目录新建工程添加文件到工程中main.c时钟STC实验箱4 IAP15W4K58S4 Keil uVision V5.29.0.0 PK51 Prof.Developers Kit Version:9.60.0.0 在STC官网发现了库函数&#xff0c;大受震撼&#xff1a; 宏晶科技官方网站 直接搜“库函数”&#xff0c;目前仅有STC15和STC8系列有库函…

vsUnit单元测试

在自定义的方法名上【右键】然后选择【创建单元测试】&#xff0c;之后在项目中就添加了一个单元测试的项目&#xff0c;找到对应的单元测试的方法[TestMethod()]特性修饰&#xff0c;将单元测试的方法中最后一句&#xff1a;Assert.Inconclusive("验证此测试方法的正确性…

hdu 6086 Rikka with String(AC自动机+状压dp)

题目链接&#xff1a;hdu 6086 Rikka with String 题意&#xff1a; 给你n个只含01的串&#xff0c;和一个长度L,现在让你构造出满足s[i]≠s[|s|−i1] for all i∈[1,|s|] &#xff0c;长度为2L&#xff0c;并且包含给出的n个串&#xff0c;问能有多少种这样的串。 题解&#x…

简单文件传输TFTP服务器搭建 Linux RHEL6

Tftp 的应用场合1、交换机或路由器升级或备份2、无盘工作站 存放boot loader3、嵌入式开发时装载系统4、大规模的服务安装布署安装1、# yum install xinetd# yum install -y tftp-server2、检查是否开机启动# chkconfig --list | grep xinetxinetd 0:off 1:off 2:…

【STC15库函数上手笔记】2、GPIO

目录硬知识IO口初始化函数测试main.c实验现象STC实验箱4 IAP15W4K58S4 Keil uVision V5.29.0.0 PK51 Prof.Developers Kit Version:9.60.0.0 硬知识 摘自《STC库函数使用参考》 IO口初始化函数 GPIO_Inilize GPIO_InitTypeDef的定义见于文件"GPIO.H"。 typede…

带有Flask的服务器端DataTable

https://github.com/SergioLlana/datatables-flask-serverside

Json-转自菜鸟教程

1. python中为什么用json有什么作用&#xff1f;&#xff1f;不是python用json&#xff0c;json是类似xml的一种通用格式&#xff0c;在很多地方都可以用。json相比xml&#xff0c;数据量更小&#xff0c;而且可以很方便的和解释型语言的结构相互转换。 2. 常用的两种Json函数&…

centos下编译安装curl拓展

---恢复内容开始--- 新的php环境没有curl拓展&#xff0c;现在用编译方式增加拓展。 一、安装curl 当前curl最新版本为7.32&#xff0c;下载地址为http://curl.haxx.se/download/curl-7.32.0.tar.gz 使用wget方式下载到相关目录 wget http://curl.haxx.se/download/curl-7.32.0…

iOS UITableView 移除单元格选中时的高亮状态

郝萌主倾心贡献&#xff0c;尊重作者的劳动成果&#xff0c;请勿转载。 如果文章对您有所帮助&#xff0c;欢迎给作者捐赠&#xff0c;支持郝萌主&#xff0c;捐赠数额随意&#xff0c;重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X&#xff1a;点我传送 在处理UITableView表格时…

【STC15库函数上手笔记】3、外部中断

目录硬知识外中断初始化函数测试main.cExti.cSTC实验箱4 IAP15W4K58S4 Keil uVision V5.29.0.0 PK51 Prof.Developers Kit Version:9.60.0.0 硬知识 摘自《STC库函数使用参考》 外中断初始化函数 Ext_Inilize EXTI_InitTypeDef的定义见于文件"Exti.H"。 typed…

Mac pycharm flask 用内网ip 运行 web

1. 菜单 run -> run 2. 选择&#xff0c;你要运行的 py 程序 3. 设置 Additional options: 为 --host0.0.0.0 &#xff0c;把 FLASK_DEBUG 的勾&#xff0c;去掉&#xff0c;如下图 4. 在 py 程序中 &#xff08;运行的主程序&#xff09;&#xff0c; 修改以下代码 …