带有自定义表和实体框架核心的身份核心角色授权

时间:2021-01-22 16:33:35

标签: asp.net entity-framework asp.net-identity blazor asp.net-core-identity

我快到了,我使用 Core Identity 实现了我的自定义身份验证,因为我已经有一些包含用户、角色的表和一个将角色分配给用户的连接表。

不要介意不好的模型属性名称,遗憾的是我必须处理一个设计非常糟糕的数据库,并且没有保存加密的密码(我做了一个解决方法,你可以在下面的代码中看到,为了跳过密码散列和它有效)。

我还从一个非常简单的角色硬编码测试开始,但我无法访问该代码。 我将我的 DbContext 称为“OracleContext”,因此我的模型是从现有数据库构建的。

我将 .Net Core 3.1 与 Blazor Server 一起使用,我已经创建了实现最少量接口的 UserStore 对象: 用户存储.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

namespace core_identity_utenza_bms.Data
{
    public class UserStore : IUserStore<Geutenti>, IUserPasswordStore<Geutenti>, IUserRoleStore<Geutenti>
    {
        private readonly OracleContext _oracleContext;

        public UserStore(OracleContext oracleContext)
        {
            _oracleContext = oracleContext;
        }
        public void Dispose()
        {
            //throw new NotImplementedException();
        }

        public async Task<string> GetUserIdAsync(Geutenti user, CancellationToken cancellationToken)
        {
            return user.Cuser.ToString();
        }

        public async Task<string> GetUserNameAsync(Geutenti user, CancellationToken cancellationToken)
        {
            return user.Ruser;
        }

        public async Task SetUserNameAsync(Geutenti user, string userName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public async Task<string> GetNormalizedUserNameAsync(Geutenti user, CancellationToken cancellationToken)
        {
            return user.Tuser;
        }

        public async Task SetNormalizedUserNameAsync(Geutenti user, string normalizedName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public async Task<IdentityResult> CreateAsync(Geutenti user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public async Task<IdentityResult> UpdateAsync(Geutenti user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public async Task<IdentityResult> DeleteAsync(Geutenti user, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public async Task<Geutenti> FindByIdAsync(string userId, CancellationToken cancellationToken)
        {
            var userQuery =
                await _oracleContext.Geutenti.Where(
                    u =>
                        u.Cuser.ToString().Equals(userId) &&
                        u.Bstor.Equals("A") &&
                        u.Csoci.Equals("MASM")).FirstOrDefaultAsync(cancellationToken);
            return userQuery;
        }

        public async Task<Geutenti> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
        {
            var userQuery =
                await _oracleContext.Geutenti.Where(
                        u =>
                            u.Ruser.Contains("ARDILLOI") &&
                            u.Bstor.Equals("A") &&
                            u.Csoci.Equals("MASM"))
                    .FirstOrDefaultAsync(cancellationToken);
            return userQuery;
        }

        public async Task SetPasswordHashAsync(Geutenti user, string passwordHash, CancellationToken cancellationToken)
        {
            //throw new NotImplementedException();
        }

        public async Task<string> GetPasswordHashAsync(Geutenti user, CancellationToken cancellationToken)
        {
            return user.CpaswDuser;
        }

        public async Task<bool> HasPasswordAsync(Geutenti user, CancellationToken cancellationToken)
        {
            return !(user.CpaswDuser == null || user.CpaswDuser.Equals(string.Empty));
        }

        /*
         * UserRole
         */
        public async Task AddToRoleAsync(Geutenti user, string roleName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public async Task RemoveFromRoleAsync(Geutenti user, string roleName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public async Task<IList<string>> GetRolesAsync(Geutenti user, CancellationToken cancellationToken)
        {
            //var userRoles = _oracleContext.Geruxute.
            return new List<string> {"BURBERO", "BARBARO"};
        }

        public async Task<bool> IsInRoleAsync(Geutenti user, string roleName, CancellationToken cancellationToken)
        {
            return new List<string> { "BURBERO", "BARBARO" }.Contains(roleName);

        }

        public async Task<IList<Geutenti>> GetUsersInRoleAsync(string roleName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }
    }
}

然后我实现了一个跳过密码散列的类: NoPasswordHasher.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;

namespace core_identity_utenza_bms.Data
{
    public class NoPasswordHasher : IPasswordHasher<Geutenti>
    {
        public string HashPassword(Geutenti user, string password)
        {
            return password;
        }

        public PasswordVerificationResult VerifyHashedPassword(Geutenti user, string hashedPassword, string providedPassword)
        {
            return hashedPassword.Equals(providedPassword) ? PasswordVerificationResult.Success : PasswordVerificationResult.Failed;
        }
    }
}

我创建了一个 RoleStore.cs 文件来检索我在 db 上的角色:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

namespace core_identity_utenza_bms.Data
{
    public class RoleStore : IRoleStore<Geruoliz>
    {
        private readonly OracleContext _oracleContext;

        public RoleStore(OracleContext oracleContext)
        {
            _oracleContext = oracleContext;
        }
        public void Dispose()
        {
            //throw new NotImplementedException();
        }

        public async Task<IdentityResult> CreateAsync(Geruoliz role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public async Task<IdentityResult> UpdateAsync(Geruoliz role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public async Task<IdentityResult> DeleteAsync(Geruoliz role, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public async Task<string> GetRoleIdAsync(Geruoliz role, CancellationToken cancellationToken)
        {
            return role.Crule.ToString();
        }

        public async Task<string> GetRoleNameAsync(Geruoliz role, CancellationToken cancellationToken)
        {
            return role.Rrule;
        }

        public async Task SetRoleNameAsync(Geruoliz role, string roleName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public async Task<string> GetNormalizedRoleNameAsync(Geruoliz role, CancellationToken cancellationToken)
        {
            return role.Rrule;
        }

        public async Task SetNormalizedRoleNameAsync(Geruoliz role, string normalizedName, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        public async Task<Geruoliz> FindByIdAsync(string roleId, CancellationToken cancellationToken)
        {
            var role = await _oracleContext.Geruoliz.Where(
                    r =>
                        r.Crule.ToString().Equals(roleId) &&
                        r.Bstor.Equals("A") &&
                        r.Csoci.Equals("MASM"))
                .FirstOrDefaultAsync(cancellationToken: cancellationToken);
            return role;
        }

        public async Task<Geruoliz> FindByNameAsync(string normalizedRoleName, CancellationToken cancellationToken)
        {
            var role = await _oracleContext.Geruoliz.Where(
                    r =>
                        r.Rrule.Equals(normalizedRoleName) &&
                        r.Bstor.Equals("A") &&
                        r.Csoci.Equals("MASM"))
                .FirstOrDefaultAsync(cancellationToken: cancellationToken);
            return role;
        }
    }
}

最后我编辑了 Startup.cs:

services.AddDbContext<OracleContext>();
services
    .AddDefaultIdentity<Geutenti>()
    .AddUserStore<UserStore>();
services.AddScoped<IPasswordHasher<Geutenti>, NoPasswordHasher>();

现在我什至无法在 UserStore.GetRolesAsync 和 UserStore.IsInRoleAsync 中输入断点,因为我想我应该通过这些检查来确定视图是否可见,例如通过使用:

>
@page "/counter"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
<AuthorizeView>
    <p>sei loggato.</p>
</AuthorizeView>
<AuthorizeView Roles="BURBERO">
    <Authorized>
        Sei un burbero!
    </Authorized>
    <NotAuthorized>
        Sei una brava persona.
    </NotAuthorized>
</AuthorizeView>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

我只在授权视图中成功,没有指定任何角色。 我尝试的最后一件事是编辑服务,例如:

services.AddDbContext<OracleContext>();
services
    .AddDefaultIdentity<Geutenti>()
    .AddUserStore<UserStore>()
    .AddRoleStore<RoleStore>();
services.AddScoped<IPasswordHasher<Geutenti>, NoPasswordHasher>();

但它给了我一个例外:

System.InvalidOperationException: 'No RoleType was specified, try AddRoles<TRole>().'

老实说,现在我对网络上零散的信息感到不知所措。 有什么帮助吗?非常感谢您的时间!

1 个答案:

答案 0 :(得分:0)

我找到了自己的路。这既是与缓存相关的问题,也与启动设置有关。 上面的所有代码都可以工作,我必须在启动中设置:

// Add identity types
services.AddDbContext<OracleContext>();
services
    .AddIdentity<Geutenti, Geruoliz>()
    .AddRoles<Geruoliz>()
    .AddDefaultTokenProviders();
// Identity Services
services.AddTransient<IUserStore<Geutenti>, UserStore>();
services.AddTransient<IRoleStore<Geruoliz>, RoleStore>();
services.AddScoped<IPasswordHasher<Geutenti>, NoPasswordHasher>();

这里的对象是:

  • OracleContext:它是来自 Entity Framework Core 的数据库上下文对象,它包装了包含我的三个用户表的数据库
  • Geutenti:用户表,包含所有相关数据(用户名、密码、电子邮件等)
  • Geruoliz:角色表
  • UserStore 和 RoleStore:实现那些接口的对象,这些接口通知 Core Identity 如何访问用户相关数据以进行身份​​验证和授权
  • NoPasswordHasher:绕过密码散列的解决方法。 (声明:这引入了一个安全漏洞,您不应该按原样保存密码,而是保存它们的哈希值)

我必须注销/清除 cookie 并重新启动项目,登录等等!