asp.net - 使用自定义表和实体框架核心的身份核心角色授权
问题描述
我快到了,我使用 Core Identity 实现了我的自定义身份验证,因为我已经有一些包含用户、角色的表和一个为用户分配角色的连接表。
不要介意糟糕的模型属性名称,遗憾的是我必须处理一个设计非常糟糕的数据库,并且没有保存未加密的密码(我做了一个解决方法,如下面的代码所示,为了跳过密码散列并且它可以工作)。
我还从一个非常简单的角色硬编码测试开始,但我无法访问该代码。我将我的 DbContext 称为“OracleContext”,因此我的模型是从现有数据库中搭建的。
我将 .Net Core 3.1 与 Blazor Server 一起使用,我创建了实现最少接口数量的 UserStore 对象: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>().'
到现在为止,老实说,我对网络上分散的信息感到不知所措。有什么帮助吗?非常感谢您的宝贵时间!
解决方案
我找到了路。这既是与缓存相关的问题,也是启动设置。上面的所有代码都可以工作,我必须在 Startup 中设置:
// 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:跳过密码哈希的解决方法。(DESCLAIM:这引入了一个安全漏洞,您永远不应该按原样保存密码,而是保存它们的哈希值)
我不得不注销/删除 cookie 并重新启动项目,登录等等!
推荐阅读
- python - 如何找出我的 Dask 数据框正在使用多少工作人员?
- awk - 在第二个文件的每一行前面打印一个文件的第一行
- c# - 如何使用syncfusion pdf获取剩余页面大小
- mysql - MySQL 选择行和分组
- java - 当我添加到 OnClickListener 上的列表视图时出现错误
- java - 以日期为数据类型将字符串转换为“yyy-MM-dd”格式
- javascript - 如何在警报组件中添加 InputText?
- java - 无法使用 jackson 将 xml 绑定到 pojo,com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:无法识别的字段
- apache-spark - 使用 Spark 和 Scala 连接 Google Cloud Platform 上的 BigQuery
- cordova - 不支持加载非cordova模块“fs”的错误“requirecordovamodule”