【发布时间】:2021-10-05 12:42:29
【问题描述】:
如何使用 ASP.NET CORE 授权 AspNetRoleClaims 和 Angular 实现 Jwt 令牌?
例如,我有以下默认角色(用户类型):
管理员(Gerencia)
用户
客户
拥有 viewRoles 声明的用户可以使用自定义声明添加自己的角色。
例如
工人
声明 canViewClients canViewInventory....
有权查看员工并对其进行编辑的用户可以从下拉列表中选择您可以在我的图片上看到的用户类型。
当用户选择用户类型时,我的应用程序会自动填写用户默认可以访问的声明。但是,用户始终可以取消选中或检查不同的声明,自动填充只是为了节省一些时间。这是我的复选框在视觉上的样子。
每个复选框代表一个声明。
回顾
- 用户类型不用于授权端点,仅用于在视觉上快速填充复选框。
- 每个复选框代表一个声明。
如何向我的 jwt cookie 添加声明/策略
这是我的 startup.cs 文件的重要部分。
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ApplicationSettings>(Configuration.GetSection("AppSettings"));
services.AddTransient<DatabaseMigrator>();
services.AddDbContext<erp_colombiaDbContext>(options => options.UseMySql(
Configuration.GetConnectionString("DefaultConnection"),
optionsBuilder => optionsBuilder.MigrationsAssembly(typeof(DesignTimeDbContextFactory).Assembly.FullName)));
services.TryAddScoped<UserManager<Employee>>();
services.TryAddScoped<SignInManager<Employee>>();
//Should I add roles/policies here?
services.AddIdentityCore<Employee>(options =>
options.SignIn.RequireConfirmedAccount = false
).AddRoles<Entities.Type>().AddEntityFrameworkStores<erp_colombiaDbContext>();
//Jwt Authentication
var key = Encoding.UTF8.GetBytes("myKey");
services.Configure<IdentityOptions>(options =>
{
options.Password.RequireDigit = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.Password.RequiredLength = 4;
});
services.AddCors();
//Jwt Authentication
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x =>
{
x.IncludeErrorDetails = true;
x.RequireHttpsMetadata = false;
x.TokenValidationParameters = new TokenValidationParameters
{
RequireSignedTokens = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
ClockSkew = TimeSpan.Zero
};
x.Events = new JwtBearerEvents
{
OnAuthenticationFailed = c =>
{
// break point here
return Task.CompletedTask;
},
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("ViewClientsPolicy",
policy => policy.RequireClaim("View Clients"));
});
//services.AddControllersWithViews();
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
services.AddMvc();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IMenuService, MenuService>();
//Service for identity user.
services.AddScoped<IEmployeeService, EmployeeService>();
//Service for identity role.
services.AddScoped<ITypeService, TypeService>();
services.AddScoped<IGeneralConfigurationService, GeneralConfigurationService>();
services.AddScoped<IComponentLocationService, ComponentLocationService>();
services.AddScoped<INewsService, NewsService>();
services.AddScoped<INewsCategoryService, NewsCategoryService>();
services.AddScoped<INewsCategoriesService, NewsCategoriesService>();
services.AddScoped<IExternalLinksService, ExternalLinksService>();
services.AddScoped<IClientService, ClientService>();
services.AddScoped<ISupplierService, SupplierService>();
services.AddScoped<IContactService, ContactService>();
services.AddScoped<IUserTypeService, UserTypeService>();
services.AddScoped<IComponentService, ComponentService>();
services.AddScoped<IFamilyService, FamilyService>();
services.AddScoped<IContractMenuService, ContractMenuService>();
services.AddScoped<IContractService, ContractService>();
services.AddScoped<IHolidayService, HolidayService>();
services.AddScoped<IExpeditionService, ExpeditionService>();
services.AddScoped<IKanbanService, KanbanService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
if (!env.IsDevelopment())
{
app.UseSpaStaticFiles();
}
app.UseRouting();
// global cors policy
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
}
}
这是我的员工的样子
[Table("erp_empleados")]
public class Employee : IdentityUser<ulong>
{
[Display(Name = "empName", ResourceType = typeof(SharedResource))]
[Column("nombre")]
public string Name { get; set; }
[Display(Name = "empLastName", ResourceType = typeof(SharedResource))]
[Column("apellido")]
public string FamilyName { get; set; }
[Display(Name = "empEmail", ResourceType = typeof(SharedResource))]
[Column("correo")]
public override string Email { get; set; }
//And many more fields
}
这是我的用户角色类的样子
[Table("erp_tipo_usuario")]
public class Type : IdentityRole<ulong>
{
}
在我的 Angular 应用程序中,我有以下代码来保护我的端点。我不确定如何修改它,所以它需要索赔? 更新我现在明白我不必更改 jwt 令牌中的任何内容,声明/角色将包含在内,这就是它的工作方式。
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private router: Router) { }
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean {
if (localStorage.getItem('token') != null)
return true;
else {
this.router.navigate(['/user/login']);
return false;
}
}
}
也登录在我的应用程序中,我有以下代码。
[HttpPost, Route("login")]
public async Task<IActionResult> Login([FromBody] LoginModel user)
{
string passowrdHashed = HashPassword(user.Password);
var userFromDb = await _userManager.FindByNameAsync(user.UserName);
if (userFromDb == null)
{
return Unauthorized();
}
else if (user != null && userFromDb.UserName==user.UserName
&& userFromDb.PasswordHash == passowrdHashed)
{
if (userFromDb.PasswordHash == HashPassword(_employeeService.DEFAULT_PASSWORD))
{
return Ok("Please change password!");
}
else
{
//*********************************************************************
//****** How to add Code to add ASP.NET Identity claims??????????????? *******
//*********************************************************************
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[] {
new Claim("UserID", "1")
new Claim(ClaimTypes.Role, role.NormalizedName),
}),
Issuer = "jcortenbach",
Expires = DateTime.UtcNow.AddHours(1),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes("superlongKeyWithALotOfWordsToMakeItMoreSecureWhichIsGoodThankYouForReadingMySecretKey@45")), SecurityAlgorithms.HmacSha256Signature)
};
var tokenHandler = new JwtSecurityTokenHandler();
var securityToken = tokenHandler.CreateToken(tokenDescriptor);
var token = tokenHandler.WriteToken(securityToken);
return Ok(new { token });
}
}
else
{
return Unauthorized();
}
}
最后,当谈到我的后端时,我认为它应该看起来像这样。例如获取客户列表代码。
[Route("api/[controller]")]
[ApiController]
public class ClientsController : ControllerBase
{
private readonly ILogger<ClientsController> _logger;
private readonly IClientService _clientService;
public ClientsController(erp_colombiaDbContext context, ILogger<ClientsController> logger, IClientService clientService)
{
_logger = logger;
_clientService = clientService;
}
// GET api/clients
// **Update** I have add [Authorize(Roles = "comercial")] and comment out the [Authorize(Policy = "ViewClientsPolicy")] and the authentication works for user role based authentication I however would like to have policy based authentication as well.
[HttpGet]
[Authorize(Roles = "comercial")]
[Authorize(Policy = "ViewClientsPolicy")]
public async Task<IEnumerable<ClientViewModel>> GetAsync()
{
ClientViewModel clientViewModel;
List<ClientViewModel> listClientViewModels = new List<ClientViewModel>();
var clients = await _clientService.GetAllClients();
foreach (var client in clients)
{
clientViewModel = new ClientViewModel();
clientViewModel.ClientId = client.ClientId;
clientViewModel.Active = client.Active;
clientViewModel.Address = client.Address;
clientViewModel.City = client.City;
clientViewModel.ClienteName = client.ClienteName;
clientViewModel.ComercialEmployeeId = client.ComercialEmployeeId;
clientViewModel.Confirmed = client.Confirmed;
clientViewModel.CountryId = client.CountryId;
clientViewModel.CreationDate = client.CreationDate;
clientViewModel.DANE = client.DANE;
clientViewModel.Department = client.Department;
clientViewModel.ElectronicBillingEmail = client.ElectronicBillingEmail;
clientViewModel.Eliminated = client.Eliminated;
clientViewModel.NIT = client.NIT;
clientViewModel.PostalCode = client.PostalCode;
clientViewModel.Phone = client.Phone;
listClientViewModels.Add(clientViewModel);
}
return listClientViewModels;
}
如果有很多拼图,我不确定下一步该做什么。非常感谢您的帮助。
问题回顾
- 如何将 asp.net 核心角色添加到声明/策略中?
- 如何将声明/策略连接到用户? 完成
- 要在启动中添加什么内容才能使声明/政策发挥作用?
- 如何向 jwt cookie 添加声明/策略?
- 如何在 Angular 中使用 jwt 声明/策略 cookie? DONE在登录控制器功能中添加jwt cookie时会自动发生
【问题讨论】:
标签: angular asp.net-core jwt