ABP 详解系列9:基于ABP框架实现RBAC(角色访问控制)

基于ABP框架实现RBAC(角色访问控制)

本文详细讲解了基于ABP框架实现RBAC(角色访问控制)的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

在业务系统需求规划过程中,通常对于诸如组织机构、用户和角色等这种基础功能,通常是将这部分功能规划到通用子域中,这也说明了,对于这部分功能来讲,是系统的基石,整个业务体系是建立于这部分基石之上的,当然,还有诸如多语言、设置管理、认证和授权等。对于这部分功能,ABP中存在这些概念,并且通过Module Zero模块完成了这些概念。

一、角色访问控制之RBAC

RBAC:Role Based Access Control,基于角色的访问控制,这在目前大多数软件中来讲已经算得上是普遍应用了,最常见的结构如下,结构简单,设计思路清晰。

在这里插入图片描述
但是也存在其它升级版的设计,诸如用户权限表、角色组、用户组的概念等,具体分类有RBAC0、RBAC1、RBAC2等,后者功能越来越强大,也越来越复杂。

  • RBAC0:是RBAC的核心思想。
  • RBAC1:是把RBAC的角色分层模型。
  • RBAC2:增加了RBAC的约束模型。
  • RBAC3:整合RBAC2 + RBAC1。

二、ABP中的RBAC

在Abp中,已经集成了这些概念,并在ModuleZero模块中实现了这些概念,基于IdentityServer4的ModuleZero模块完成了封装。对于我们大多数以业务为中心的开发人员来讲,不应该又去造一个轮子,而是应该开好这辆车。首先看下Abp中的RBAC模型

在这里插入图片描述
在这其中权限表中记录了用户与权限,角色与权限两部分。

对于权限通常指的是功能权限和数据权限两部分,一般来讲,大多指的是功能权限,这种通过角色与权限进行管理即可,如还有用户部分的功能区分,则可以再使用上用户与权限,而对于数据权限,可以利用用户与权限部分,个人用的比较少,但是,可以想象到这么一个场景,针对于一家门店内的多个店长,角色相同即相应的权限相同,但各自关心的数据来源不同,关心东部、南部等数据,而不关心西部、北部数据,因此可以在数据层面进行划分,比如设置数据来源,东南西北,对于数据来源进行权限关联,这样一来用户本身如果拥有东部数据权限,则只能看到东部数据。

三、ABP Zero的人身认证关系分析

3.1 AbpUser

ABP Zero 中扩展的Asp.Net Identity实体类: AbpUser, AbpRole。
AbpUser: 代表user的Entity。其实现了Asp.Net Identity的IUser接口。

在这里插入图片描述

3.2 AbpRole

AbpRole: 代表role的Entity。其实现了Asp.Net Identity的IRole接口。
一个role代表一组权限。ABP建议检查user的permission而非role以判断user是否可以执行某个操作。
在这里插入图片描述
在这里插入图片描述

ABP Zero 中扩展Asp.Net Identity重管理实体的类: AbpUserStore, AbpUserManager,AbpRoleStore,AbpRoleManager。

3.3 AbpUserStore

AbpUserStore

主要实现了ASP.NET Identity Framework中与user操作相关的接口:`IUserPasswordStore<TUser,long>,IUserEmailStore<TUser,> long>,IUserLoginStore<TUser, long>,IUserRoleStore long>,IQueryableUserStore<TUser, long>。

同时也实现了IUserPermissionStore<TTenant, TUser>接口。该类通过IRepository<TUser,
long>,IRepository<UserLogin, long>,IRepository<UserRole,> long>,IRepository,IRepository<UserPermissionSetting, long>实例完成User实体的CRUD操作以及与User关联关系的CRUD操作。

在这里插入图片描述

3.4 AbpUserManager

AbpUserManager:继承扩展了ASP.NET Identity Framework中UserManager<TUser, long>类。实现了与User相关的领域服务。
在这里插入图片描述

3.5 AbpRoleStore

AbpRoleStore

其实现了Asp.Net Identity的IQueryableRoleStore接口。
通过IRepository,IRepository<UserRole, long>和IRepository<RolePermissionSetting, long>实例完成Role及与role相关的permission/user实体的CRUD操作。
在这里插入图片描述

3.6 AbpRoleManager

AbpRoleManager<TTenant, TRole, TUser>:继承自Asp.Net Identity的RoleManager<TRole, int>类。这是一个抽象类,实际项目需要指定具体的TTenant, TRole,
TUser类型来扩展这个抽象类。该抽象类实现了与Role相关的领域逻辑。
在这里插入图片描述

3.7 UserRole

UserRole:实现了CreationAuditedEntity的实体类。描述User 和 Role的关系。
在这里插入图片描述

3.8 PermissionSetting

PermissionSetting:代表user/role 和 permission的关系实体类
在这里插入图片描述

3.9 OrganizationUnit

OrganizationUnit:实现了FullAuditedEntity的实体类,用于表示Organization的实体
**在这里插入图片描述**

3.10 UserLogin

UserLogin:实体类用于保存通过外部授权服务授权的用户的登入信息。
在这里插入图片描述

3.11 RolePermissionCacheItem

RolePermissionCacheItem:这个类实例被用于缓存,其HashSet类型的GrantedPermissions和ProhibitedPermissions对象用于保存role的权限
在这里插入图片描述
UserPermissionCacheItem:这个类实例被用于缓存,其HashSet类型的GrantedPermissions和ProhibitedPermissions对象用于保存user的权限
在这里插入图片描述
PermissionEqualityComparer : 实现了IEqualityComparer接口中的Equal和GetHashCode方法,用于比较两个permission.

AbpRolePermissionCacheItemInvalidator:用于定义响应RolePermissionSetting和AbpRoleBase实体改变事件的处理函数。实际完成的工作就是将相应的缓存对象从缓存中删除。

在这里插入图片描述
AbpUserPermissionCacheItemInvalidator:用于定义响应UserPermissionSetting,UserRole和AbpUser实体改变事件的处理函数。实际完成的工作就是将相应的缓存对象从缓存中删除。

DefaultExternalAuthenticationSource<TTenant, TUser>/IExternalAuthenticationSource<TTenant, TUser>:通过外部身份认证源(比如Facebook)的认证信息创建User.

3.12 PermissionChecker

PermissionChecker:继承自IPermissionChecker,检查user是否被授予了某个权限。

在这里插入图片描述
IMayHaveOrganizationUnit:如果entity可能和Organization有关联,就可以考虑实现该接口。

IMustHaveOrganizationUnit:如果entity一定和Organization有关联,就可以考虑实现该接口。

IOrganizationUnitSettings:定义了一项和OrganizationUnit相关的设置:MaxUserMembershipCount,以及获取和修改MaxUserMembershipCount的方法。

OrganizationUnitSettings:通过settingManager实现了IOrganizationUnitSettings定义的属性和方法

在这里插入图片描述

3.13 OrganizationUnitManager

OrganizationUnitManager:实现与OrganizationUnit相关的领域逻辑。使用IRepository<OrganizationUnit, long>实例完成OrganizationUnit实体的CRUD操作。

在这里插入图片描述

3.14 IdentityFrameworkClaimsAbpSession

IdentityFrameworkClaimsAbpSession : 继承自ClaimsAbpSession。通过 ASP.NET Identity framework接口获取当前用户的userID
在这里插入图片描述
IdentityResultExtensions:为ASP.NET Identity 的IdentityResult类型添加了如下的扩展方法。这些方法主要用于本地化error message.

在这里插入图片描述
IdentityResultExtensions定义了一个用于map消息和本地化资源文件中key的字典对象,这个字典对象帮助获取消息的本地化后的消息。

在这里插入图片描述

四、权限声明及应用代码

在Abp中,需要首先在Core层/Authorization/PermissionNames.cs中声明权限,Abp权限部分设计原则是:先声明再使用。

/// <summary>
/// 权限命名
/// </summary>
public static class PermissionNames
{
    #region 顶级权限
    public const string Pages = "Pages";
    #endregion

    #region 基础支撑平台
    public const string Pages_Frame = "Pages.Frame";

    #region 租户管理
    public const string Pages_Frame_Tenants = "Pages.Frame.Tenants";
    #endregion

    #region 组织机构
    public const string Pages_Frame_OrganizationUnits = "Pages.Frame.OrganizationUnits";
    public const string Pages_Frame_OrganizationUnits_Create = "Pages.Frame.OrganizationUnits.Create";
    public const string Pages_Frame_OrganizationUnits_Update = "Pages.Frame.OrganizationUnits.Update";
    public const string Pages_Frame_OrganizationUnits_Delete = "Pages.Frame.OrganizationUnits.Delete";
    #endregion

    #region 用户管理
    public const string Pages_Frame_Users = "Pages.Frame.Users";
    public const string Pages_Frame_Users_Create = "Pages.Frame.Users.Create";
    public const string Pages_Frame_Users_Update = "Pages.Frame.Users.Update";
    public const string Pages_Frame_Users_Delete = "Pages.Frame.Users.Delete";
    public const string Pages_Frame_Users_ResetPassword = "Pages.Frame.Users.ResetPassword";
    #endregion

    #region 角色管理
    public const string Pages_Frame_Roles = "Pages.Roles";
    public const string Pages_Frame_Roles_Create = "Pages.Frame.Roles.Create";
    public const string Pages_Frame_Roles_Update = "Pages.Frame.Roles.Update";
    public const string Pages_Frame_Roles_Delete = "Pages.Frame.Roles.Delete";
    #endregion

}

然后在Core层/Authorization/XXXAuthorizationProvider.cs中设置具体权限,在此处设置权限时,可以根据权限设计时候的职责划分,比如如果仅仅是多租户需要这部分,那便设置权限范围为多租户即可。

public class SurroundAuthorizationProvider : AuthorizationProvider
{
    public override void SetPermissions(IPermissionDefinitionContext context)
    {
        #region 顶级权限
        var pages = context.CreatePermission(PermissionNames.Pages, L("Pages"));
        #endregion

        #region 基础支撑平台
        var frame = pages.CreateChildPermission(PermissionNames.Pages_Frame, L("Frame"));

        #region 租户管理
        frame.CreateChildPermission(PermissionNames.Pages_Frame_Tenants, L("Tenants"), multiTenancySides: MultiTenancySides.Host);
        #endregion

        #region 组织机构
        var organizationUnits = frame.CreateChildPermission(PermissionNames.Pages_Frame_OrganizationUnits, L("OrganizationUnits"));
        organizationUnits.CreateChildPermission(PermissionNames.Pages_Frame_OrganizationUnits_Create, L("CreateOrganizationUnit"));
        organizationUnits.CreateChildPermission(PermissionNames.Pages_Frame_OrganizationUnits_Update, L("EditOrganizationUnit"));
        organizationUnits.CreateChildPermission(PermissionNames.Pages_Frame_OrganizationUnits_Delete, L("DeleteOrganizationUnit"));
        #endregion

        #region 用户管理
        var users = frame.CreateChildPermission(PermissionNames.Pages_Frame_Users, L("Users"));
        users.CreateChildPermission(PermissionNames.Pages_Frame_Users_Create, L("CreateUser"));
        users.CreateChildPermission(PermissionNames.Pages_Frame_Users_Update, L("UpdateUser"));
        users.CreateChildPermission(PermissionNames.Pages_Frame_Users_Delete, L("DeleteUser"));
        users.CreateChildPermission(PermissionNames.Pages_Frame_Users_ResetPassword, L("ResetPassword"));
        #endregion

        #region 角色管理
        var roles = frame.CreateChildPermission(PermissionNames.Pages_Frame_Roles, L("Roles"));
        roles.CreateChildPermission(PermissionNames.Pages_Frame_Roles_Create, L("CreateRole"));
        roles.CreateChildPermission(PermissionNames.Pages_Frame_Roles_Update, L("UpdateRole"));
        roles.CreateChildPermission(PermissionNames.Pages_Frame_Roles_Delete, L("DeleteRole"));
        #endregion
    }
}

在设置完毕后,需要将该类集成到Core层/XXXCoreModule当前模块中,才能使得该部分权限设置生效。

//配置权限管理
Configuration.Authorization.Providers.Add<SurroundAuthorizationProvider>();

作为业务的入口,菜单是较为直观的体现方式,现在可以,为菜单分配权限了,拥有权限的人才能看的到菜单,同时后台方法中也要有权限判定,菜单仅作为前端入口上的控制,权限判定作为后端的控制。在MVC层的Startup/XXXNavigationProvider.cs中完成菜单的配置工作,可以配置多级菜单,每个菜单可以配置相应的权限,在生成菜单判定时,如果父级菜单权限不足,则直接会跳过子级菜单的判定。

new MenuItemDefinition(//基础支撑
    PageNames.FrameManage,
    L(PageNames.FrameManage),
    icon: "&#xe828;",
    requiredPermissionName: PermissionNames.Pages_Frame
).AddItem(
    new MenuItemDefinition(//组织机构
        PageNames.OrganizationUnits,
        L(PageNames.OrganizationUnits),
        url: "/OrganizationUnits",
        icon: "&#xe6cb;",
        requiredPermissionName: PermissionNames.Pages_Frame_OrganizationUnits
    )
).AddItem(
    new MenuItemDefinition(//用户管理
        PageNames.Users,
        L(PageNames.Users),
        url: "/Users",
        icon: "&#xe6cb;",
        requiredPermissionName: PermissionNames.Pages_Frame_Users
    )
).AddItem(
    new MenuItemDefinition(//角色管理
        PageNames.Roles,
        L(PageNames.Roles),
        url: "/Roles",
        icon: "&#xe6cb;",
        requiredPermissionName: PermissionNames.Pages_Frame_Roles
    )
).AddItem(
    new MenuItemDefinition(//系统设置
        PageNames.HostSettings,
        L(PageNames.HostSettings),
        url: "/HostSettings",
        icon: "&#xe6cb;",
        requiredPermissionName: PermissionNames.Pages_Frame_HostSettings
    )
)

在前端页面上,对于按钮级别的控制也通过权限判定,Abp提供了判定方法,利用Razor语法进行按钮控制

@if (await PermissionChecker.IsGrantedAsync(PermissionNames.Pages_Core_DataDictionary_Create))
{
    <button class="layui-btn layuiadmin-btn-dataDictionary" data-type="addDataDictionary">添加类型</button>
}

在后端方法上,通常我喜欢直接在应用服务中的方法上做权限判定(当然也可以前移到MVC层,但是这样一来,针对于WebApi形式的Host层,又得多加一次判定了),利用AbpAuthorize特性,判定该方法需要哪几个权限才能访问,而在mvc的控制器上做访问认证。

[AbpAuthorize(PermissionNames.Pages_Core_DataDictionary_Create)]
private async Task CreateDataDictionaryAsync(CreateOrUpdateDataDictionaryInput input)
{

}

1、角色与权限

在Abp中,角色信息存储在abprole表中,角色与权限间的关联存储在abppermission这张表中,一个角色有多个权限,如果某个角色的权限被去掉了,这张表中的相关记录将由abp负责删除,我们只需要完成掌控哪些权限是这个角色有的就行。Abp中已经完成了角色的所有操作,但是前端部分采用的是bootstrap弄的,将其改造一波,成为layui风格。
在这里插入图片描述
在创建角色中,主要是将选中的权限挂钩到具体的某个角色上,该部分代码沿用abp中自带的角色权限处理方法。

在创建角色中,主要是将选中的权限挂钩到具体的某个角色上,该部分代码沿用abp中自带的角色权限处理方法。

```csharp
private async Task CreateRole(CreateOrUpdateRoleInput input)
{
    var role = ObjectMapper.Map<Role>(input.Role);
    role.SetNormalizedName();

    CheckErrors(await _roleManager.CreateAsync(role));

    var grantedPermissions = PermissionManager
        .GetAllPermissions()
        .Where(p => input.PermissionNames.Contains(p.Name))
        .ToList();

    await _roleManager.SetGrantedPermissionsAsync(role, grantedPermissions);
}

指定角色Id,租户Id及之前声明的权限名称,在abppermission中可查看到具体角色权限。

在这里插入图片描述

2、用户与角色

一个用户可以承担多个角色,履行不同角色的义务,作为一个业务系统最基本的单元,abp中提供了这些概念并在Module Zero模块中已经完成了对用户的一系列操作,用户信息存储在AbpUsers表中,用户直接关联的角色保存在AbpUserRoles表中,abp中MVC版本采用的是bootstrap风格,因此,用layui风格完成一次替换,并且,改动一些页面布局。

在这里插入图片描述

至此,修改整合用户、角色和权限加入到系统中初步完成了,至于一些更为丰富的功能,待逐步加入中,车子再好,司机也得睡觉。

Abp版本中,由于是土耳其大佬所开发的习惯,针对于姓和名做了拆分,因此对于我们的使用要做一次处理,我这先简单处理了一下,并且在业务系统中,邮箱时有时无,因此也需要进行考虑

[AbpAuthorize(PermissionNames.Pages_Frame_Users_Create)]
private async Task CreateUser(CreateOrUpdateUserInput input)
{
    var user = ObjectMapper.Map<User>(input.User);
    user.TenantId = AbpSession.TenantId;
    user.IsEmailConfirmed = true;
    user.Name = "Name";
    user.Surname = "Surname";
    //user.EmailAddress = string.Empty;

    await UserManager.InitializeOptionsAsync(AbpSession.TenantId);
    foreach (var validator in _passwordValidators)
    {
        CheckErrors(await validator.ValidateAsync(UserManager, user, AppConsts.DefaultPassword));
    }

    user.Password = _passwordHasher.HashPassword(user, AppConsts.DefaultPassword);

    await _userManager.InitializeOptionsAsync(AbpSession.TenantId);

    CheckErrors(await _userManager.CreateAsync(user, AppConsts.DefaultPassword));

    if (input.AssignedRoleNames != null)
    {
        CheckErrors(await _userManager.SetRoles(user, input.AssignedRoleNames));
    }

    if (input.OrganizationUnitIds != null)
    {
        await _userManager.SetOrganizationUnitsAsync(user, input.OrganizationUnitIds);
    }

    CurrentUnitOfWork.SaveChanges();
}

此处对用户个人单独的权限没有去做处理,依照Abp的文档有那么一句话,大多数应用程序中,基于角色的已经足够使用了,如果想声明特定权限给用户,那么针对于用户本身的角色权限则被覆盖。

至此,修改整合用户、角色和权限加入到系统中初步完成了,至于一些更为丰富的功能,待逐步加入中,车子再好,司机也得睡觉。

五 、ABP的登录流程

abp登录管理器 LogInManager

ABP的用户有多种,默认注册的用户名密码,LDAP 等,登陆的代码流程如下

TokenAuthController.Authenticate(…) -->
LogInManager.LoginAsync(usernameOrEmailAddress, password, tenancyName) --> AbpLogInManager
这在Core 下
LogInManager 默认没有override, 继承父类的方法
LoginAsyn 下面

  • LoginAsyncInternal // 判断不正常的登陆用户信息,执行 CreateLoginResultAsync,
  • AbpUserClaimsPrincipalFactory.createAsync().获取Claims
  • SaveLoginAttemptAsync// 保存登陆记录,userLoginAttemp 这个table

AbpLogInManager.TryLoginFromExternalAuthenticationSources 这个方法会遍历登陆的方法,如LADP 等。
比如LDAP 登陆时,会执行到这个方法,如果登陆成功,这里会创建用户等,会把密码hashcode存下来。

abp重构登录(示例代码)

其他资料见 https://www.136.la/au/show-63710.html

  1. a、Core层 Authorization.Users.UserStore.cs
 public class UserStore : AbpUserStore<Role, User>
    {
        private readonly IRepository<User, long> _userRepository;

        public UserStore(
            IUnitOfWorkManager unitOfWorkManager,
            IRepository<User, long> userRepository,
            IRepository<Role> roleRepository,
            IAsyncQueryableExecuter asyncQueryableExecuter,
            IRepository<UserRole, long> userRoleRepository,
            IRepository<UserLogin, long> userLoginRepository,
            IRepository<UserClaim, long> userClaimRepository,
            IRepository<UserPermissionSetting, long> userPermissionSettingRepository,
            IRepository<UserOrganizationUnit, long> userOrganizationUnitRepository,
            IRepository<OrganizationUnitRole, long> organizationUnitRoleRepository)
            : base(
                unitOfWorkManager,
                userRepository,
                roleRepository,
                asyncQueryableExecuter,
                userRoleRepository,
                userLoginRepository,
                userClaimRepository,
                userPermissionSettingRepository,
                userOrganizationUnitRepository,
                organizationUnitRoleRepository)
        {
            _userRepository = userRepository;
        }

        /// <summary>
        /// 根据账号获取用户
        /// </summary>
        /// <param name="account"></param>
        /// <returns></returns>
        public virtual async Task<User> FindByAccountAsync(string account)
        {
            account = account.ToLower();
            return await _userRepository.FirstOrDefaultAsync(
                user => user.UserName.ToLower() == account
            );
        }
    }
  1. b、Core层 Authorization.LogInManager.cs
  public class LogInManager : AbpLogInManager<Tenant, Role, User>
    {

        private readonly UserStore _userStore;
        private readonly AbpUserManager<Role, User> _userManager;

        public LogInManager(
            UserManager userManager,
            IMultiTenancyConfig multiTenancyConfig,
            IRepository<Tenant> tenantRepository,
            IUnitOfWorkManager unitOfWorkManager,
            ISettingManager settingManager,
            IRepository<UserLoginAttempt, long> userLoginAttemptRepository,
            IUserManagementConfig userManagementConfig,
            IIocResolver iocResolver,
            IPasswordHasher<User> passwordHasher,
            RoleManager roleManager,
            UserClaimsPrincipalFactory claimsPrincipalFactory,
            UserStore userStore)
            : base(
                  userManager,
                  multiTenancyConfig,
                  tenantRepository,
                  unitOfWorkManager,
                  settingManager,
                  userLoginAttemptRepository,
                  userManagementConfig,
                  iocResolver,
                  passwordHasher,
                  roleManager,
                  claimsPrincipalFactory)
        {
            _userStore = userStore;
            _userManager = userManager;
        }

        /// <summary>
        /// 自定义登录
        /// </summary>
        /// <param name="account">账号、手机号、身份证号</param>
        /// <param name="password">明文密码</param>
        /// <returns></returns>
        [UnitOfWork]
        public virtual async Task<AbpLoginResult<Tenant, User>> LoginCustomAsync(string account, string password)
        {
            var result = await LoginCustomAsyncInternal(account, password);

            //保存用户尝试登录的记录
            await SaveLoginAttemptAsync(result, null, account);
            return result;
        }

        protected virtual async Task<AbpLoginResult<Tenant, User>> LoginCustomAsyncInternal(string account, string password)
        {
            if (account.IsNullOrEmpty() || password.IsNullOrEmpty())
            {
                throw new ArgumentException("account or password");
            }

            //不启用租户,获取默认租户
            Tenant tenant = await GetDefaultTenantAsync();

            int? tenantId = tenant?.Id;
            using (UnitOfWorkManager.Current.SetTenantId(tenantId))
            {
                //根据用户名获取用户信息
                var user = await _userStore.FindByAccountAsync(account);
                if (user == null)
                {
                    return new AbpLoginResult<Tenant, User>(AbpLoginResultType.UnknownExternalLogin, tenant);
                }

                //验证用户的密码是否正确
                var verificationResult = _userManager.PasswordHasher.VerifyHashedPassword(user, user.Password, password);
                if (verificationResult != PasswordVerificationResult.Success)
                {
                    if (await TryLockOutAsync(tenantId, user.Id))
                    {
                        return new AbpLoginResult<Tenant, User>(AbpLoginResultType.LockedOut, tenant, user);
                    }

                    return new AbpLoginResult<Tenant, User>(AbpLoginResultType.InvalidPassword, tenant, user);
                }

                //重置用户登录失败次数
                await _userManager.ResetAccessFailedCountAsync(user);

                //生成登录结果
                return await CreateLoginResultAsync(user, tenant);
            }
        }
    }
  1. c、Web.Core层
添加方法:

        /// <summary>
        /// 自定义登录
        /// </summary>
        /// <param name="userName">账号、身份证、手机号</param>
        /// <param name="password"></param>
        /// <returns></returns>
        private async Task<AbpLoginResult<Tenant, User>> GetCustomLoginResultAsync(string userName, string password)
        {
            var loginResult = await _logInManager.LoginCustomAsync(userName, password);

            switch (loginResult.Result)
            {
                case AbpLoginResultType.Success:
                    return loginResult;
                default:
                    throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(loginResult.Result, userName, null);
            }
        }
重构方法:

        [HttpPost]
        public async Task<AuthenticateResultModel> Authenticate([FromBody] AuthenticateModel model)
        {
            //var loginResult = await GetLoginResultAsync(
            //    model.UserNameOrEmailAddress,
            //    model.Password,
            //    GetTenancyNameOrNull()
            //);

            //自定义登录获取结果
            var loginResult = await GetCustomLoginResultAsync(
                model.UserNameOrEmailAddress,
                model.Password
            );

            var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity));

            return new AuthenticateResultModel
            {
                AccessToken = accessToken,
                EncryptedAccessToken = GetEncryptedAccessToken(accessToken),
                ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds,
                UserId = loginResult.User.Id
            };
        }

六 abp修改当前用户密码

/// <summary>
        /// 修改当前登录用户密码
        /// </summary>
        /// <returns></returns>
        [AbpAuthorize]
        public async Task ChangePassword(ChangePasswordInput input)
        {
            input.OldPassword = input.OldPassword.Trim();
            input.NewPassword = input.NewPassword.Trim();

            //判断旧密码是否正确
            if (string.IsNullOrWhiteSpace(input.OldPassword) || string.IsNullOrWhiteSpace(input.NewPassword))
            {
                throw new UserFriendlyException("密码不能为空");
            }

            if (input.OldPassword == input.NewPassword)
            {
                throw new UserFriendlyException("新旧密码不能相同");
            }

            //获取abp用户
            var user = await _userManager.GetUserByIdAsync(AbpSession.UserId.Value);

            //判断新密码是否正确
            var result = _passwordHasher.VerifyHashedPassword(user, user.Password, input.OldPassword);
            if (result == PasswordVerificationResult.Failed)
            {
                throw new UserFriendlyException("旧密码错误");
            }

            //新密码hash
            var hash = _passwordHasher.HashPassword(user, input.NewPassword);
            user.Password = hash;
            await _userManager.UpdateAsync(user);
        }
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值