nhu*_*uvy 2 c# jwt asp.net-core asp.net-core-webapi asp.net-core-identity
我正在使用 .NET 版本5.0.100-rc.1.20452.10、ASP.NET Core Web API、Microsoft SQL Server 2019、JWT 令牌。我有Startup.cs
using Microsoft.AspNetCore.Authentication.JwtBearer;\nusing Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Identity;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.FileProviders;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.IdentityModel.Tokens;\nusing shadow.Data;\nusing shadow.Models;\nusing shadow.Services;\nusing System.IO;\nusing System.Text;\n\nnamespace shadow\n{\n public class Startup\n {\n public Startup(IConfiguration configuration)\n {\n Configuration = configuration;\n }\n\n public IConfiguration Configuration { get; }\n\n public void ConfigureServices(IServiceCollection services)\n {\n services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));\n services.AddHttpContextAccessor();\n //services.AddCors();\n services.AddCors(options =>\n {\n options.AddPolicy("CorsPolicy",\n builder => builder.AllowAnyOrigin()\n .AllowAnyMethod()\n .AllowAnyHeader());\n });\n services.AddSingleton<IUriService>(o =>\n {\n var accessor = o.GetRequiredService<IHttpContextAccessor>();\n var request = accessor.HttpContext.Request;\n var uri = string.Concat(request.Scheme, "://", request.Host.ToUriComponent());\n return new UriService(uri);\n });\n services.AddIdentity<ApplicationUser, IdentityRole>(options =>\n {\n //options.Password.RequireDigit = true;\n //options.Password.RequireLowercase = true;\n options.Password.RequiredLength = 6;\n }).AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();\n services\n .AddAuthentication(auth =>\n {\n auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;\n auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;\n })\n\n .AddJwtBearer(options =>\n {\n options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters\n {\n ValidateIssuer = true,\n ValidateAudience = true,\n ValidAudience = Configuration["AuthSettings:Audience"],\n ValidIssuer = Configuration["AuthSettings:Issuer"],\n RequireExpirationTime = true,\n IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["AuthSettings:Key"])),\n ValidateIssuerSigningKey = true\n };\n });\n services.AddAuthorization(options =>\n {\n options.FallbackPolicy = new AuthorizationPolicyBuilder()\n .RequireAuthenticatedUser()\n .Build();\n\n });\n services.AddScoped<IUserService, UserService>();\n services.AddTransient<IMailService, SendGridMailService>(); \n services.AddControllers();\n services.AddRazorPages();\n services.AddControllers(options => options.SuppressAsyncSuffixInActionNames = false);\n services.AddMvc().AddJsonOptions(options =>\n {\n //options.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;\n options.JsonSerializerOptions.PropertyNamingPolicy = null;\n });\n }\n\n public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n {\n if (env.IsDevelopment())\n {\n app.UseDeveloperExceptionPage();\n }\n else\n {\n app.UseHsts();\n }\n //app.UseHttpsRedirection();\n app.UseRouting();\n // app.UseCors(options => options.WithOrigins("http://localhost:4200")\n //.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());\n app.UseCors("CorsPolicy");\n app.UseAuthentication();\n app.UseAuthorization();\n // Server: https://shorten.news/static-file/content/10992.mp3\n // Local: http://localhost:5000/static-file/content/10992.mp3\n app.UseStaticFiles(new StaticFileOptions\n {\n FileProvider = new PhysicalFileProvider(\n // Path.Combine(env.ContentRootPath, @"c:\\audio\\")),\n // Path.Combine(@"c:\\audio\\")),\n Path.Combine(@"D:\\shadow_backend\\Upload\\files\\")\n ),\n RequestPath = "/static-file",\n OnPrepareResponse = context =>\n {\n context.Context.Response.Headers["Access-Control-Allow-Origin"] = "*";\n }\n });\n\n app.UseEndpoints(endpoints =>\n {\n endpoints.MapControllers();\n });\n app.Run(async (context) =>\n {\n await context.Response.WriteAsync("cound not find anything");\n });\n }\n }\n\n}\nRun Code Online (Sandbox Code Playgroud)\n文件IUserService.cs
using Microsoft.AspNetCore.WebUtilities;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.IdentityModel.Tokens;\nusing shadow.Models;\nusing shadow.Shared;\nusing System;\nusing System.IdentityModel.Tokens.Jwt;\nusing System.Linq;\nusing System.Security.Claims;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace shadow.Services\n{\n\n public interface IUserService\n {\n\n Task<UserManagerResponse> RegisterUserAsync(RegisterViewModel model);\n Task<UserManagerResponse> LoginUserAsync(LoginViewModel model);\n Task<UserManagerResponse> LogoutUserAsync(LoginViewModel model);\n Task<UserManagerResponse> ConfirmEmailAsync(string userId, string token);\n Task<UserManagerResponse> ForgetPasswordAsync(string email);\n Task<UserManagerResponse> ResetPasswordAsync(ResetPasswordViewModel model);\n Task<UserManagerResponse> ChangePasswordAsync(ChangePasswordViewModel model);\n }\n\n public class UserService : IUserService\n {\n private Microsoft.AspNetCore.Identity.UserManager<ApplicationUser> _userManger;\n private IConfiguration _configuration;\n private IMailService _mailService;\n\n public UserService(Microsoft.AspNetCore.Identity.UserManager<ApplicationUser> userManager, IConfiguration configuration, IMailService mailService)\n {\n _userManger = userManager;\n _configuration = configuration;\n _mailService = mailService;\n }\n\n public async Task<UserManagerResponse> RegisterUserAsync(RegisterViewModel model)\n {\n if (model == null)\n {\n throw new NullReferenceException("Reigster Model is null");\n }\n if (model.Password != model.ConfirmPassword)\n {\n return new UserManagerResponse\n {\n Message = "Confirm password doesn\'t match the password",\n IsSuccess = false,\n };\n }\n var identityUser = new ApplicationUser\n {\n Email = model.Email,\n UserName = model.Email,\n About = model.About,\n SecondMobile = model.SecondMobile,\n Fullname = model.Fullname,\n AliasName = model.AliasName,\n Created = DateTime.Now,\n Modified = DateTime.Now\n };\n var result = await _userManger.CreateAsync(identityUser, model.Password);\n\n if (result.Succeeded)\n {\n var confirmEmailToken = await _userManger.GenerateEmailConfirmationTokenAsync(identityUser);\n var encodedEmailToken = Encoding.UTF8.GetBytes(confirmEmailToken);\n var validEmailToken = WebEncoders.Base64UrlEncode(encodedEmailToken);\n string url = $"{_configuration["AppUrl"]}/api/auth/ConfirmEmail?userId={identityUser.Id}&token={validEmailToken}";\n await _mailService.SendEmailAsync(identityUser.Email, "Confirm your email", $"<h1>Welcome to Trustee app</h1>" +\n $"<p>Please confirm your email by <a href=\'{url}\'>clicking here</a></p>");\n return new UserManagerResponse\n {\n Message = "User created successfully!",\n IsSuccess = true,\n };\n }\n return new UserManagerResponse\n {\n Message = "User did not create",\n IsSuccess = false,\n Errors = result.Errors.Select(e => e.Description)\n };\n }\n\n /// <summary>\n /// \xc4\x90\xc4\x83ng nh\xe1\xba\xadp.\n /// </summary>\n /// <param name="model"></param>\n /// <returns></returns>\n public async Task<UserManagerResponse> LoginUserAsync(LoginViewModel model)\n {\n var user = await _userManger.FindByEmailAsync(model.Email);\n if (user == null)\n {\n return new UserManagerResponse\n {\n Message = "There is no user with that Email address",\n IsSuccess = false,\n };\n }\n var result = await _userManger.CheckPasswordAsync(user, model.Password);\n if (!result)\n {\n return new UserManagerResponse\n {\n Message = "Invalid password",\n IsSuccess = false,\n };\n }\n var claims = new[]\n {\n new Claim("Email", model.Email),\n new Claim(ClaimTypes.NameIdentifier, user.Id),\n };\n var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["AuthSettings:Key"]));\n var token = new JwtSecurityToken(\n issuer: _configuration["AuthSettings:Issuer"],\n audience: _configuration["AuthSettings:Audience"],\n claims: claims,\n expires: DateTime.Now.AddDays(30),\n signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256));\n string tokenAsString = new JwtSecurityTokenHandler().WriteToken(token);\n return new UserManagerResponse\n {\n Message = tokenAsString,\n IsSuccess = true,\n ExpireDate = token.ValidTo\n };\n }\n\n // \xc4\x90\xc4\x83ng xu\xe1\xba\xa5t.\n public async Task<UserManagerResponse> LogoutUserAsync(LoginViewModel model)\n {\n var user = await _userManger.FindByEmailAsync(model.Email);\n if (user == null)\n {\n return new UserManagerResponse\n {\n Message = "There is no user with that Email address",\n IsSuccess = false,\n };\n }\n var result = await _userManger.CheckPasswordAsync(user, model.Password);\n if (!result)\n {\n return new UserManagerResponse\n {\n Message = "Invalid password",\n IsSuccess = false,\n };\n }\n var claims = new[]\n {\n new Claim("Email", model.Email),\n new Claim(ClaimTypes.NameIdentifier, user.Id),\n };\n var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["AuthSettings:Key"]));\n var token = new JwtSecurityToken(\n issuer: _configuration["AuthSettings:Issuer"],\n audience: _configuration["AuthSettings:Audience"],\n claims: claims,\n expires: DateTime.Now.AddDays(30),\n signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256));\n string tokenAsString = new JwtSecurityTokenHandler().WriteToken(token);\n return new UserManagerResponse\n {\n Message = tokenAsString,\n IsSuccess = true,\n ExpireDate = token.ValidTo\n };\n }\n\n public async Task<UserManagerResponse> ConfirmEmailAsync(string userId, string token)\n {\n var user = await _userManger.FindByIdAsync(userId);\n if (user == null)\n {\n return new UserManagerResponse { IsSuccess = false, Message = "User not found" };\n }\n var decodedToken = WebEncoders.Base64UrlDecode(token);\n string normalToken = Encoding.UTF8.GetString(decodedToken);\n var result = await _userManger.ConfirmEmailAsync(user, normalToken);\n if (result.Succeeded)\n {\n return new UserManagerResponse { Message = "Email confirmed successfully!", IsSuccess = true };\n }\n return new UserManagerResponse\n {\n IsSuccess = false,\n Message = "Email did not confirm",\n Errors = result.Errors.Select(e => e.Description)\n };\n }\n\n public async Task<UserManagerResponse> ForgetPasswordAsync(string email)\n {\n var user = await _userManger.FindByEmailAsync(email);\n if (user == null)\n {\n return new UserManagerResponse { IsSuccess = false, Message = "No user associated with email", };\n }\n var token = await _userManger.GeneratePasswordResetTokenAsync(user);\n var encodedToken = Encoding.UTF8.GetBytes(token);\n var validToken = WebEncoders.Base64UrlEncode(encodedToken);\n string url = $"{_configuration["AppUrl"]}/ResetPassword?email={email}&token={validToken}";\n await _mailService.SendEmailAsync(email, "Reset Password", "<h1>Follow the instructions to reset your password</h1>" +\n $"<p>To reset your password <a href=\'{url}\'>Click here</a></p>");\n return new UserManagerResponse\n {\n IsSuccess = true,\n Message = "Reset password URL has been sent to the email successfully!"\n };\n }\n\n public async Task<UserManagerResponse> ResetPasswordAsync(ResetPasswordViewModel model)\n {\n var user = await _userManger.FindByEmailAsync(model.Email);\n if (user == null)\n {\n return new UserManagerResponse { IsSuccess = false, Message = "No user associated with email", };\n }\n if (model.NewPassword != model.ConfirmPassword)\n {\n return new UserManagerResponse { IsSuccess = false, Message = "Password doesn\'t match its confirmation", };\n }\n var decodedToken = WebEncoders.Base64UrlDecode(model.Token);\n string normalToken = Encoding.UTF8.GetString(decodedToken);\n var result = await _userManger.ResetPasswordAsync(user, normalToken, model.NewPassword);\n if (result.Succeeded)\n {\n return new UserManagerResponse { Message = "Password has been reset successfully!", IsSuccess = true };\n }\n return new UserManagerResponse\n {\n Message = "Something went wrong",\n IsSuccess = false,\n Errors = result.Errors.Select(e => e.Description)\n };\n }\n \n public async Task<UserManagerResponse> ChangePasswordAsync(ChangePasswordViewModel model)\n {\n var tokenString = model.Token; \n var jwtEncodedString = tokenString.Substring(7); // trim \'Bearer \' from the start since its just a prefix for the token string\n var token = new JwtSecurityToken(jwtEncodedString: jwtEncodedString);\n string email = token.Claims.First(c => c.Type == "Email").Value;\n Console.WriteLine("email => " + email);\n var user = await _userManger.FindByEmailAsync(email);\n if (user == null)\n {\n return new UserManagerResponse { IsSuccess = false, Message = "No user associated with email", };\n }\n if (model.NewPassword != model.ConfirmPassword)\n {\n return new UserManagerResponse { IsSuccess = false, Message = "Password doesn\'t match its confirmation", };\n }\n var token2 = await _userManger.GeneratePasswordResetTokenAsync(user);\n var result = await _userManger.ResetPasswordAsync(user, token2, model.NewPassword);\n if (result.Succeeded)\n {\n return new UserManagerResponse { Message = "Password has been changed successfully!", IsSuccess = true };\n }\n return new UserManagerResponse\n {\n Message = "Something went wrong",\n IsSuccess = false,\n Errors = result.Errors.Select(e => e.Description)\n };\n } \n }\n\n}\nRun Code Online (Sandbox Code Playgroud)\n文件appsettings.json
{\n "ConnectionStrings": {\n "DefaultConnection": "Server=.;Database=foo;User Id=sa; Password=SecrEt_STring;Trusted_Connection=False;MultipleActiveResultSets=True"\n },\n "Logging": {\n "LogLevel": {\n "Default": "Information",\n "Microsoft": "Warning",\n "Microsoft.Hosting.Lifetime": "Information"\n }\n },\n "AllowedHosts": "*",\n "AuthSettings": {\n "Key": "This is the key that we will use in the encryption",\n "Audience": "http://example.io",\n "Issuer": "http://example.io"\n },\n "SendGridAPIKey": "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",\n "AppUrl": "http://localhost:5002"\n}\n\nRun Code Online (Sandbox Code Playgroud)\n在控制器中
\nusing Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Extensions.Configuration;\nusing shadow.Data;\nusing shadow.DTO;\nusing shadow.Models;\nusing shadow.Services;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace shadow.Controllers\n{\n [Route("[controller]")]\n [ApiController]\n public class AssetItemController : ControllerBase\n {\n private IUserService _userService;\n private IMailService _mailService;\n private IConfiguration _configuration;\n private Appli
您实际上并没有向令牌添加角色。每个角色都应该是一个主张,就像这样。
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);
Run Code Online (Sandbox Code Playgroud)
然后添加allClaims到 JWT,如下所示:
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));
Run Code Online (Sandbox Code Playgroud)
让我知道它是如何工作的。
编辑:抱歉,忘记AddRange返回 void;
| 归档时间: |
|
| 查看次数: |
3168 次 |
| 最近记录: |