用了两天的时间研究了在Asp.Net WebApi 项目中如何实现注册、登录、身份验证功能。此项目使用JWT(Json Web Token)来进行身份验证。
用户服务
ASP.NET Core用户服务负责与用户身份验证,注册和管理相关的所有数据库交互和核心业务逻辑。
该文件的顶部包含一个定义用户服务的接口,下面是实现该接口的具体用户服务类。该类的底部包含一些私有方法,用于创建和验证存储在数据库中的散列密码。
- 通过Emain和Password来登录服务,Authenticate方法调用VerifyPasswordHash来验证Email和密码是否正确来进行登录授权。
- public User Authenticate(string email, string password)
- {
- if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password))
- return null;
- var user = _iUserRepository.GetUserByEmail(email);
- // check if username exists
- if (user == null)
- return null;
- // check if password is correct
- if (!VerifyPasswordHash(password, user.PasswordHash, user.PasswordSalt))
- return null;
- // authentication successful
- return user;
- }
复制代码- private static bool VerifyPasswordHash(string password, byte[] storedHash, byte[] storedSalt)
- {
- if (password == null) throw new ArgumentNullException(nameof(password));
- if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("Value cannot be empty or whitespace only string.", "password");
- if (storedHash.Length != 64) throw new ArgumentException("Invalid length of password hash (64 bytes expected).", "passwordHash");
- if (storedSalt.Length != 128) throw new ArgumentException("Invalid length of password salt (128 bytes expected).", "passwordHash");
- using (var hmac = new System.Security.Cryptography.HMACSHA512(storedSalt))
- {
- var computedHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
- for (int i = 0; i < computedHash.Length; i++)
- {
- if (computedHash[i] != storedHash[i]) return false;
- }
- }
- return true;
- }
复制代码
- 用户注册时需要创建新用户并将用户数据存放到数据库中
- public User Create(User user, string password)
- {
- // validation
- if (string.IsNullOrWhiteSpace(password))
- throw new AppException("Password is required");
- if (_iUserRepository.Any(x => x.Email == user.Email))
- throw new AppException("Email "" + user.Email + "" is already taken");
- if (_iUserRepository.Any(x => x.UserName == user.UserName))
- throw new AppException("Username "" + user.UserName + "" is already taken");
- CreatePasswordHash(password, out var passwordHash, out var passwordSalt);
- user.PasswordHash = passwordHash;
- user.PasswordSalt = passwordSalt;
- _iUserRepository.Add(user);
- return user;
- }
复制代码
对密码进行加密存储 - private static void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
- {
- if (password == null) throw new ArgumentNullException(nameof(password));
- if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("Value cannot be empty or whitespace only string.", "password");
- using (var hmac = new System.Security.Cryptography.HMACSHA512())
- {
- passwordSalt = hmac.Key;
- passwordHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
- }
- }
复制代码
- 用户信息更新及删除代码
- public void Update(User userParam, string password = null)
- {
- var user = _iUserRepository.GetById(userParam.Id);
- if (user == null)
- throw new AppException("User not found");
- if (userParam.UserName != user.UserName)
- {
- // username has changed so check if the new username is already taken
- if (_iUserRepository.Any(x => x.UserName == userParam.UserName))
- throw new AppException("Username " + userParam.UserName + " is already taken");
- }
- // update user properties
- user.FirstName = userParam.FirstName;
- user.LastName = userParam.LastName;
- user.UserName = userParam.UserName;
- // update password if it was entered
- if (!string.IsNullOrWhiteSpace(password))
- {
- CreatePasswordHash(password, out var passwordHash, out var passwordSalt);
- user.PasswordHash = passwordHash;
- user.PasswordSalt = passwordSalt;
- }
- _iUserRepository.Update(user);
- }
- public void Delete(string id)
- {
- var user = _iUserRepository.GetById(id);
- if (user != null)
- {
- _iUserRepository.Remove(user);
- }
- }
复制代码
用户实体、用户模型及数据上下文 - public class User
- {
- public string Id { get; set; }
- public string FirstName { get; set; }
- public string LastName { get; set; }
- public string UserName { get; set; }
- public string Email { get; set; }
- public byte[] PasswordHash { get; set; }
- public byte[] PasswordSalt { get; set; }
- }
复制代码- public class UserModel
- {
- public string Id { get; set; }
- public string FirstName { get; set; }
- public string LastName { get; set; }
- public string UserName { get; set; }
- public string Email { get; set; }
- public string Password { get; set; }
- }
复制代码- public class VueContext : DbContext
- {
- public VueContext(DbContextOptions<VueContext> options)
- : base(options)
- {
- }
- public DbSet<User> User { get; set; }
- }
复制代码
应用程序设置文件
/appsettings.json - {
- "AppSettings": {
- "Secret": "THIS IS USED TO SIGN AND VERIFY JWT TOKENS, REPLACE IT WITH YOUR OWN SECRET, IT CAN BE ANY STRING"
- },
- "Logging": {
- "IncludeScopes": false,
- "LogLevel": {
- "Default": "Warning"
- }
- },
- "AllowedHosts": "*",
- "ConnectionStrings": {
- "VueDatabase": "serverName;Database=VueDb;Trusted_Connection=True;"
- }
- }
复制代码
在Startup.cs中配置身份验证
添加以下代码到ConfigureServices方法中以添加身份验证服务 - // configure strongly typed settings objects
- var appSettingsSection = Configuration.GetSection("AppSettings");
- services.Configure<AppSettings>(appSettingsSection);
- // configure jwt authentication
- var appSettings = appSettingsSection.Get<AppSettings>();
- var key = Encoding.ASCII.GetBytes(appSettings.Secret);
- services.AddAuthentication(x =>
- {
- x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
- x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
- })
- .AddJwtBearer(x =>
- {
- x.Events = new JwtBearerEvents
- {
- OnTokenValidated = context =>
- {
- var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>();
- var userId = context.Principal.Identity.Name;
- var user = userService.GetById(userId);
- if (user == null)
- {
- // return unauthorized if user no longer exists
- context.Fail("Unauthorized");
- }
- return Task.CompletedTask;
- }
- };
- x.RequireHttpsMetadata = false;
- x.SaveToken = true;
- x.TokenValidationParameters = new TokenValidationParameters
- {
- ValidateIssuerSigningKey = true,
- IssuerSigningKey = new SymmetricSecurityKey(key),
- ValidateIssuer = false,
- ValidateAudience = false
- };
- });
复制代码
对应用配置身份验证,添加以下代码到Configure中
核心代码大概就这些。最近看了微软官方文档,但是并没有发现详细教程,最终发现一篇博客,提取核心内容搬运记录下来。
参考文献
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 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |