ASP.NET核心身份[Authorize(Roles ="ADMIN"))]不起作用

编程入门 行业动态 更新时间:2024-10-24 13:19:32
本文介绍了ASP.NET核心身份[Authorize(Roles ="ADMIN"))]不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我正在使用.NET版本5.0.100-rc.1.20452.10,ASP.NET Core Web API,Microsoft SQL Server 2019,JWT令牌.我有Startup.cs

I am using .NET version 5.0.100-rc.1.20452.10 , ASP.NET Core Web API, Microsoft SQL Server 2019, JWT token. I have Startup.cs

using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Hosting; using Microsoft.IdentityModel.Tokens; using shadow.Data; using shadow.Models; using shadow.Services; using System.IO; using System.Text; namespace shadow { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddHttpContextAccessor(); //services.AddCors(); services.AddCors(options => { options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader()); }); services.AddSingleton<IUriService>(o => { var accessor = o.GetRequiredService<IHttpContextAccessor>(); var request = accessor.HttpContext.Request; var uri = string.Concat(request.Scheme, "://", request.Host.ToUriComponent()); return new UriService(uri); }); services.AddIdentity<ApplicationUser, IdentityRole>(options => { //options.Password.RequireDigit = true; //options.Password.RequireLowercase = true; options.Password.RequiredLength = 6; }).AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders(); services .AddAuthentication(auth => { auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidAudience = Configuration["AuthSettings:Audience"], ValidIssuer = Configuration["AuthSettings:Issuer"], RequireExpirationTime = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["AuthSettings:Key"])), ValidateIssuerSigningKey = true }; }); services.AddAuthorization(options => { options.FallbackPolicy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); }); services.AddScoped<IUserService, UserService>(); services.AddTransient<IMailService, SendGridMailService>(); services.AddControllers(); services.AddRazorPages(); services.AddControllers(options => options.SuppressAsyncSuffixInActionNames = false); services.AddMvc().AddJsonOptions(options => { //options.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase; options.JsonSerializerOptions.PropertyNamingPolicy = null; }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseHsts(); } //app.UseHttpsRedirection(); app.UseRouting(); // app.UseCors(options => options.WithOrigins("localhost:4200") //.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()); app.UseCors("CorsPolicy"); app.UseAuthentication(); app.UseAuthorization(); // Server: shorten.news/static-file/content/10992.mp3 // Local: localhost:5000/static-file/content/10992.mp3 app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider( // Path.Combine(env.ContentRootPath, @"c:\audio\")), // Path.Combine(@"c:\audio\")), Path.Combine(@"D:\shadow_backend\Upload\files\") ), RequestPath = "/static-file", OnPrepareResponse = context => { context.Context.Response.Headers["Access-Control-Allow-Origin"] = "*"; } }); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); app.Run(async (context) => { await context.Response.WriteAsync("cound not find anything"); }); } } }

文件IUserService.cs

using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; using shadow.Models; using shadow.Shared; using System; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Security.Claims; using System.Text; using System.Threading.Tasks; namespace shadow.Services { public interface IUserService { Task<UserManagerResponse> RegisterUserAsync(RegisterViewModel model); Task<UserManagerResponse> LoginUserAsync(LoginViewModel model); Task<UserManagerResponse> LogoutUserAsync(LoginViewModel model); Task<UserManagerResponse> ConfirmEmailAsync(string userId, string token); Task<UserManagerResponse> ForgetPasswordAsync(string email); Task<UserManagerResponse> ResetPasswordAsync(ResetPasswordViewModel model); Task<UserManagerResponse> ChangePasswordAsync(ChangePasswordViewModel model); } public class UserService : IUserService { private Microsoft.AspNetCore.Identity.UserManager<ApplicationUser> _userManger; private IConfiguration _configuration; private IMailService _mailService; public UserService(Microsoft.AspNetCore.Identity.UserManager<ApplicationUser> userManager, IConfiguration configuration, IMailService mailService) { _userManger = userManager; _configuration = configuration; _mailService = mailService; } public async Task<UserManagerResponse> RegisterUserAsync(RegisterViewModel model) { if (model == null) { throw new NullReferenceException("Reigster Model is null"); } if (model.Password != model.ConfirmPassword) { return new UserManagerResponse { Message = "Confirm password doesn't match the password", IsSuccess = false, }; } var identityUser = new ApplicationUser { Email = model.Email, UserName = model.Email, About = model.About, SecondMobile = model.SecondMobile, Fullname = model.Fullname, AliasName = model.AliasName, Created = DateTime.Now, Modified = DateTime.Now }; var result = await _userManger.CreateAsync(identityUser, model.Password); if (result.Succeeded) { var confirmEmailToken = await _userManger.GenerateEmailConfirmationTokenAsync(identityUser); var encodedEmailToken = Encoding.UTF8.GetBytes(confirmEmailToken); var validEmailToken = WebEncoders.Base64UrlEncode(encodedEmailToken); string url = $"{_configuration["AppUrl"]}/api/auth/ConfirmEmail?userId={identityUser.Id}&token={validEmailToken}"; await _mailService.SendEmailAsync(identityUser.Email, "Confirm your email", $"<h1>Welcome to Trustee app</h1>" + $"<p>Please confirm your email by <a href='{url}'>clicking here</a></p>"); return new UserManagerResponse { Message = "User created successfully!", IsSuccess = true, }; } return new UserManagerResponse { Message = "User did not create", IsSuccess = false, Errors = result.Errors.Select(e => e.Description) }; } /// <summary> /// Đăng nhập. /// </summary> /// <param name="model"></param> /// <returns></returns> public async Task<UserManagerResponse> LoginUserAsync(LoginViewModel model) { var user = await _userManger.FindByEmailAsync(model.Email); if (user == null) { return new UserManagerResponse { Message = "There is no user with that Email address", IsSuccess = false, }; } var result = await _userManger.CheckPasswordAsync(user, model.Password); if (!result) { return new UserManagerResponse { Message = "Invalid password", IsSuccess = false, }; } var claims = new[] { new Claim("Email", model.Email), new Claim(ClaimTypes.NameIdentifier, user.Id), }; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["AuthSettings:Key"])); var token = new JwtSecurityToken( issuer: _configuration["AuthSettings:Issuer"], audience: _configuration["AuthSettings:Audience"], claims: claims, expires: DateTime.Now.AddDays(30), signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)); string tokenAsString = new JwtSecurityTokenHandler().WriteToken(token); return new UserManagerResponse { Message = tokenAsString, IsSuccess = true, ExpireDate = token.ValidTo }; } // Đăng xuất. public async Task<UserManagerResponse> LogoutUserAsync(LoginViewModel model) { var user = await _userManger.FindByEmailAsync(model.Email); if (user == null) { return new UserManagerResponse { Message = "There is no user with that Email address", IsSuccess = false, }; } var result = await _userManger.CheckPasswordAsync(user, model.Password); if (!result) { return new UserManagerResponse { Message = "Invalid password", IsSuccess = false, }; } var claims = new[] { new Claim("Email", model.Email), new Claim(ClaimTypes.NameIdentifier, user.Id), }; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["AuthSettings:Key"])); var token = new JwtSecurityToken( issuer: _configuration["AuthSettings:Issuer"], audience: _configuration["AuthSettings:Audience"], claims: claims, expires: DateTime.Now.AddDays(30), signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)); string tokenAsString = new JwtSecurityTokenHandler().WriteToken(token); return new UserManagerResponse { Message = tokenAsString, IsSuccess = true, ExpireDate = token.ValidTo }; } public async Task<UserManagerResponse> ConfirmEmailAsync(string userId, string token) { var user = await _userManger.FindByIdAsync(userId); if (user == null) { return new UserManagerResponse { IsSuccess = false, Message = "User not found" }; } var decodedToken = WebEncoders.Base64UrlDecode(token); string normalToken = Encoding.UTF8.GetString(decodedToken); var result = await _userManger.ConfirmEmailAsync(user, normalToken); if (result.Succeeded) { return new UserManagerResponse { Message = "Email confirmed successfully!", IsSuccess = true }; } return new UserManagerResponse { IsSuccess = false, Message = "Email did not confirm", Errors = result.Errors.Select(e => e.Description) }; } public async Task<UserManagerResponse> ForgetPasswordAsync(string email) { var user = await _userManger.FindByEmailAsync(email); if (user == null) { return new UserManagerResponse { IsSuccess = false, Message = "No user associated with email", }; } var token = await _userManger.GeneratePasswordResetTokenAsync(user); var encodedToken = Encoding.UTF8.GetBytes(token); var validToken = WebEncoders.Base64UrlEncode(encodedToken); string url = $"{_configuration["AppUrl"]}/ResetPassword?email={email}&token={validToken}"; await _mailService.SendEmailAsync(email, "Reset Password", "<h1>Follow the instructions to reset your password</h1>" + $"<p>To reset your password <a href='{url}'>Click here</a></p>"); return new UserManagerResponse { IsSuccess = true, Message = "Reset password URL has been sent to the email successfully!" }; } public async Task<UserManagerResponse> ResetPasswordAsync(ResetPasswordViewModel model) { var user = await _userManger.FindByEmailAsync(model.Email); if (user == null) { return new UserManagerResponse { IsSuccess = false, Message = "No user associated with email", }; } if (model.NewPassword != model.ConfirmPassword) { return new UserManagerResponse { IsSuccess = false, Message = "Password doesn't match its confirmation", }; } var decodedToken = WebEncoders.Base64UrlDecode(model.Token); string normalToken = Encoding.UTF8.GetString(decodedToken); var result = await _userManger.ResetPasswordAsync(user, normalToken, model.NewPassword); if (result.Succeeded) { return new UserManagerResponse { Message = "Password has been reset successfully!", IsSuccess = true }; } return new UserManagerResponse { Message = "Something went wrong", IsSuccess = false, Errors = result.Errors.Select(e => e.Description) }; } public async Task<UserManagerResponse> ChangePasswordAsync(ChangePasswordViewModel model) { var tokenString = model.Token; var jwtEncodedString = tokenString.Substring(7); // trim 'Bearer ' from the start since its just a prefix for the token string var token = new JwtSecurityToken(jwtEncodedString: jwtEncodedString); string email = token.Claims.First(c => c.Type == "Email").Value; Console.WriteLine("email => " + email); var user = await _userManger.FindByEmailAsync(email); if (user == null) { return new UserManagerResponse { IsSuccess = false, Message = "No user associated with email", }; } if (model.NewPassword != model.ConfirmPassword) { return new UserManagerResponse { IsSuccess = false, Message = "Password doesn't match its confirmation", }; } var token2 = await _userManger.GeneratePasswordResetTokenAsync(user); var result = await _userManger.ResetPasswordAsync(user, token2, model.NewPassword); if (result.Succeeded) { return new UserManagerResponse { Message = "Password has been changed successfully!", IsSuccess = true }; } return new UserManagerResponse { Message = "Something went wrong", IsSuccess = false, Errors = result.Errors.Select(e => e.Description) }; } } }

文件appsettings.json

{ "ConnectionStrings": { "DefaultConnection": "Server=.;Database=foo;User Id=sa; Password=SecrEt_STring;Trusted_Connection=False;MultipleActiveResultSets=True" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "AuthSettings": { "Key": "This is the key that we will use in the encryption", "Audience": "example.io", "Issuer": "example.io" }, "SendGridAPIKey": "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", "AppUrl": "localhost:5002" }

在控制器中

using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using shadow.Data; using shadow.DTO; using shadow.Models; using shadow.Services; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; namespace shadow.Controllers { [Route("[controller]")] [ApiController] public class AssetItemController : ControllerBase { private IUserService _userService; private IMailService _mailService; private IConfiguration _configuration; private ApplicationDbContext _db; public AssetItemController(IUserService userService, IMailService mailService, IConfiguration configuration, ApplicationDbContext context /*, SignInManager<IdentityUser> signInManager */) { _userService = userService; _mailService = mailService; _configuration = configuration; _db = context; // _signInManager = signInManager; } // Admin liệt kê tất cả các tài sản. [HttpGet] [Route("all")] [Authorize(Roles ="ADMIN")] public async Task<ActionResult<AssetItem>> GetAllAssetItems() { var a = await Task.Run(() => _db.AssetItems); if (a != null) { return Ok(a.ToList()); } else { return NoContent(); } } // Liệt kê tất cả các tài sản theo user_id. [HttpGet] [Route("user/{userId}")] public async Task<ActionResult<IEnumerable<AssetItem>>> GetAllAssetItemsByUserId(string userId) { var assetListByUserId = await Task.Run(() => _db.AssetItems.Where(x => x.UserId == userId).ToList()); if (assetListByUserId != null) { return Ok(assetListByUserId); } else { return NoContent(); } } // Xem chi tiet asset_item theo id cua no. [HttpGet] [Route("{assetItemId}")] public async Task<ActionResult<IEnumerable<AssetItem>>> ViewAssetItemById(int assetItemId) { var assetListByUserId = await Task.Run(() => _db.AssetItems.Where(x => x.Id == assetItemId).FirstOrDefault()); if (assetListByUserId != null) { return Ok(assetListByUserId); } else { return NoContent(); } } // Xóa tài sản. [HttpDelete("{id}")] public async Task<ActionResult<string>> DeleteAssetItem(int id) { var item = _db.AssetItems.Find(id); if (item != null) { _db.AssetItems.Remove(item); await _db.SaveChangesAsync(); return Ok("ok"); } else { return NotFound(); } } // POST localhost:5002/AssetItem [HttpPost] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)] [Authorize] public async Task<ActionResult<AssetItem>> Add([FromForm] AssetItemDTO input) { if (ModelState.IsValid) { AssetItem assetItem = new AssetItem(); if (input.AssetTypeId != null) { assetItem.AssetTypeId = input.AssetTypeId; } if (input.UserId != null) { assetItem.UserId = input.UserId; } if (input.TrustedPersonId != null) { assetItem.TrustedPersonId = input.TrustedPersonId; } if (input.TrustedContent != null) { assetItem.TrustedContent = input.TrustedContent; } if (input.Description != null) { assetItem.Description = input.Description; } assetItem.Created = DateTime.Now; if (input.file != null) { if (IsImageFile(input.file)) { string imgPath = await WriteFile(input.file); assetItem.ImagePath = imgPath; } else { return BadRequest(new { message = "Invalid file extension" }); } } _db.AssetItems.Add(assetItem); await _db.SaveChangesAsync(); return Ok(assetItem); } else { return BadRequest(ModelState); } } // Edit 1 tài sản. // PUT localhost:5002/AssetItem [HttpPut("{id}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)] [Authorize] public async Task<ActionResult<AssetItem>> Edit([FromForm] AssetItemDTO input, int id) { if (ModelState.IsValid) { var foo = _db.AssetItems.Find(id); if (!String.IsNullOrEmpty(input.TrustedContent)) { foo.TrustedContent = input.TrustedContent; }else { foo.TrustedContent = null; } if (input.file != null) { string imgPath = await WriteFile(input.file); foo.ImagePath = imgPath; } else { foo.ImagePath = null; } if (!String.IsNullOrEmpty(input.Description)) { foo.Description = input.Description; } else { foo.Description = null; } foo.AssetTypeId = input.AssetTypeId; if (input.TrustedPersonId != null) { foo.TrustedPersonId = input.TrustedPersonId; } // Hiện chưa ghi nhận user_modified. Cần xem lại Requirement. if (!String.IsNullOrEmpty(input.UserModified)) { foo.UserModified = input.UserModified; } else { foo.UserModified = null; } foo.Modified = DateTime.Now; _db.Update(foo); await _db.SaveChangesAsync(); return Ok(foo); } else { return BadRequest(ModelState); } } private bool IsImageFile(IFormFile file) { try { var extension = "." + file.FileName.Split('.')[file.FileName.Split('.').Length - 1]; return (extension == ".png" || extension == ".jpg" || extension == ".bmp" || extension == ".gif" || extension == ".tif"); } catch { return false; } } private async Task<string> WriteFile(IFormFile file) { string fileName = ""; try { var extension = "." + file.FileName.Split('.')[file.FileName.Split('.').Length - 1]; fileName = DateTime.Now.Ticks + extension; //Create a new Name for the file due to security reasons. var pathBuilt = Path.Combine(Directory.GetCurrentDirectory(), "Upload\\file"); if (!Directory.Exists(pathBuilt)) { Directory.CreateDirectory(pathBuilt); } var path = Path.Combine(Directory.GetCurrentDirectory(), "Upload\\files", fileName); using (var stream = new FileStream(path, FileMode.Create)) { await file.CopyToAsync(stream); } return fileName; } catch (Exception e) { // } return fileName; } } }

数据库

select * from AspNetUsers; select * from AspNetUserRoles; select * from AspNetRoles;

结果

添加[Authorize(Roles ="ADMIN")]时,显示403 Forbidden.

如何使按角色授权"起作用?

How to make Authorize by Role work?

推荐答案

您实际上并未在令牌中添加角色.每个角色都应该是这样的主张.

You are not actually adding roles to the token. Each role should be a claim, like this.

new Claim(ClaimTypes.Role, "<role name">));

例如.

var claims = new[] { new Claim("Email", model.Email), new Claim(ClaimTypes.NameIdentifier, user.Id), }; var roles = await _userManger.GetRolesAsync(user); // note: you have a typo in "_userManger" var claimsWithRoles = roles.Select(role => new Claim(ClaimTypes.Role, role)); var allClaims = claims.Concat(claimsWithRoles);

然后将allClaims添加到JWT,如下所示:

Then add allClaims to the JWT, like this:

var token = new JwtSecurityToken( issuer: _configuration["AuthSettings:Issuer"], audience: _configuration["AuthSettings:Audience"], claims: allClaims , // note how we add all claims, including the ones for roles, here expires: DateTime.Now.AddDays(30), signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256));

让我知道它是如何工作的.

Let me know how it works.

对不起,忘记了AddRange返回空;

Sorry, forgot AddRange returns void;

更多推荐

ASP.NET核心身份[Authorize(Roles ="ADMIN"))]不起作用

本文发布于:2023-11-16 10:12:24,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1603353.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:不起作用   核心   身份   NET   ASP

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!