找回密码
 会员注册
查看: 192|回复: 0

Asp.Net Core WebApi 身份验证、注册、用户管理

[复制链接]

1389

主题

5

回帖

496万

积分

管理员

积分
4962990
发表于 2024-2-29 08:36:49 | 显示全部楼层 |阅读模式


用了两天的时间研究了在Asp.Net WebApi 项目中如何实现注册、登录、身份验证功能。此项目使用JWT(Json Web Token)来进行身份验证。

用户服务

ASP.NET Core用户服务负责与用户身份验证,注册和管理相关的所有数据库交互和核心业务逻辑。

该文件的顶部包含一个定义用户服务的接口,下面是实现该接口的具体用户服务类。该类的底部包含一些私有方法,用于创建和验证存储在数据库中的散列密码。

  1. 通过Emain和Password来登录服务,Authenticate方法调用VerifyPasswordHash来验证Email和密码是否正确来进行登录授权。
  1. public User Authenticate(string email, string password)
  2. {
  3. if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password))
  4. return null;
  5. var user = _iUserRepository.GetUserByEmail(email);
  6. // check if username exists
  7. if (user == null)
  8. return null;
  9. // check if password is correct
  10. if (!VerifyPasswordHash(password, user.PasswordHash, user.PasswordSalt))
  11. return null;
  12. // authentication successful
  13. return user;
  14. }
复制代码
  1. private static bool VerifyPasswordHash(string password, byte[] storedHash, byte[] storedSalt)
  2. {
  3. if (password == null) throw new ArgumentNullException(nameof(password));
  4. if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("Value cannot be empty or whitespace only string.", "password");
  5. if (storedHash.Length != 64) throw new ArgumentException("Invalid length of password hash (64 bytes expected).", "passwordHash");
  6. if (storedSalt.Length != 128) throw new ArgumentException("Invalid length of password salt (128 bytes expected).", "passwordHash");
  7. using (var hmac = new System.Security.Cryptography.HMACSHA512(storedSalt))
  8. {
  9. var computedHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
  10. for (int i = 0; i < computedHash.Length; i++)
  11. {
  12. if (computedHash[i] != storedHash[i]) return false;
  13. }
  14. }
  15. return true;
  16. }
复制代码
  1. 用户注册时需要创建新用户并将用户数据存放到数据库中
  1. public User Create(User user, string password)
  2. {
  3. // validation
  4. if (string.IsNullOrWhiteSpace(password))
  5. throw new AppException("Password is required");
  6. if (_iUserRepository.Any(x => x.Email == user.Email))
  7. throw new AppException("Email "" + user.Email + "" is already taken");
  8. if (_iUserRepository.Any(x => x.UserName == user.UserName))
  9. throw new AppException("Username "" + user.UserName + "" is already taken");
  10. CreatePasswordHash(password, out var passwordHash, out var passwordSalt);
  11. user.PasswordHash = passwordHash;
  12. user.PasswordSalt = passwordSalt;
  13. _iUserRepository.Add(user);
  14. return user;
  15. }
复制代码

对密码进行加密存储

  1. private static void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
  2. {
  3. if (password == null) throw new ArgumentNullException(nameof(password));
  4. if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("Value cannot be empty or whitespace only string.", "password");
  5. using (var hmac = new System.Security.Cryptography.HMACSHA512())
  6. {
  7. passwordSalt = hmac.Key;
  8. passwordHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
  9. }
  10. }
复制代码
  1. 用户信息更新及删除代码
  1. public void Update(User userParam, string password = null)
  2. {
  3. var user = _iUserRepository.GetById(userParam.Id);
  4. if (user == null)
  5. throw new AppException("User not found");
  6. if (userParam.UserName != user.UserName)
  7. {
  8. // username has changed so check if the new username is already taken
  9. if (_iUserRepository.Any(x => x.UserName == userParam.UserName))
  10. throw new AppException("Username " + userParam.UserName + " is already taken");
  11. }
  12. // update user properties
  13. user.FirstName = userParam.FirstName;
  14. user.LastName = userParam.LastName;
  15. user.UserName = userParam.UserName;
  16. // update password if it was entered
  17. if (!string.IsNullOrWhiteSpace(password))
  18. {
  19. CreatePasswordHash(password, out var passwordHash, out var passwordSalt);
  20. user.PasswordHash = passwordHash;
  21. user.PasswordSalt = passwordSalt;
  22. }
  23. _iUserRepository.Update(user);
  24. }
  25. public void Delete(string id)
  26. {
  27. var user = _iUserRepository.GetById(id);
  28. if (user != null)
  29. {
  30. _iUserRepository.Remove(user);
  31. }
  32. }
复制代码

用户实体、用户模型及数据上下文

  1. public class User
  2. {
  3. public string Id { get; set; }
  4. public string FirstName { get; set; }
  5. public string LastName { get; set; }
  6. public string UserName { get; set; }
  7. public string Email { get; set; }
  8. public byte[] PasswordHash { get; set; }
  9. public byte[] PasswordSalt { get; set; }
  10. }
复制代码
  1. public class UserModel
  2. {
  3. public string Id { get; set; }
  4. public string FirstName { get; set; }
  5. public string LastName { get; set; }
  6. public string UserName { get; set; }
  7. public string Email { get; set; }
  8. public string Password { get; set; }
  9. }
复制代码
  1. public class VueContext : DbContext
  2. {
  3. public VueContext(DbContextOptions<VueContext> options)
  4. : base(options)
  5. {
  6. }
  7. public DbSet<User> User { get; set; }
  8. }
复制代码

应用程序设置文件

/appsettings.json

  1. {
  2. "AppSettings": {
  3. "Secret": "THIS IS USED TO SIGN AND VERIFY JWT TOKENS, REPLACE IT WITH YOUR OWN SECRET, IT CAN BE ANY STRING"
  4. },
  5. "Logging": {
  6. "IncludeScopes": false,
  7. "LogLevel": {
  8. "Default": "Warning"
  9. }
  10. },
  11. "AllowedHosts": "*",
  12. "ConnectionStrings": {
  13. "VueDatabase": "serverName;Database=VueDb;Trusted_Connection=True;"
  14. }
  15. }
复制代码

在Startup.cs中配置身份验证

添加以下代码到ConfigureServices方法中以添加身份验证服务

  1. // configure strongly typed settings objects
  2. var appSettingsSection = Configuration.GetSection("AppSettings");
  3. services.Configure<AppSettings>(appSettingsSection);
  4. // configure jwt authentication
  5. var appSettings = appSettingsSection.Get<AppSettings>();
  6. var key = Encoding.ASCII.GetBytes(appSettings.Secret);
  7. services.AddAuthentication(x =>
  8. {
  9. x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
  10. x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
  11. })
  12. .AddJwtBearer(x =>
  13. {
  14. x.Events = new JwtBearerEvents
  15. {
  16. OnTokenValidated = context =>
  17. {
  18. var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>();
  19. var userId = context.Principal.Identity.Name;
  20. var user = userService.GetById(userId);
  21. if (user == null)
  22. {
  23. // return unauthorized if user no longer exists
  24. context.Fail("Unauthorized");
  25. }
  26. return Task.CompletedTask;
  27. }
  28. };
  29. x.RequireHttpsMetadata = false;
  30. x.SaveToken = true;
  31. x.TokenValidationParameters = new TokenValidationParameters
  32. {
  33. ValidateIssuerSigningKey = true,
  34. IssuerSigningKey = new SymmetricSecurityKey(key),
  35. ValidateIssuer = false,
  36. ValidateAudience = false
  37. };
  38. });
复制代码

对应用配置身份验证,添加以下代码到Configure中

  1. app.UseAuthentication();
复制代码

核心代码大概就这些。最近看了微软官方文档,但是并没有发现详细教程,最终发现一篇博客,提取核心内容搬运记录下来。

参考文献

http://jasonwatmore.com/post/2018/06/26/aspnet-core-21-simple-api-for-authentication-registration-and-user-management#user-service-cs

https://neilq.github.io/2018/07/14/secure-your-asp-net-core-2-1-api-1-issuing-a-JWT/

https://www.cnblogs.com/RainingNight/p/jwtbearer-authentication-in-asp-net-core.html


来源:https://blog.csdn.net/qq_33319140/article/details/83722130
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-26 11:33 , Processed in 0.949687 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表