Asp.Net Core WebApi認証、登録、ユーザー管理

10905 ワード

Asp.Net Core WebApi認証、登録、ユーザー管理

  • ユーザサービス
  • ユーザエンティティ、ユーザモデルおよびデータコンテキスト
  • アプリケーション設定ファイル
  • はStartupです.csでの認証の構成
  • 参考文献
  • 2日間かけて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 options)
                : base(options)
            {
            }
    
            public DbSet 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;"
      }
    }
    
    

    スタータープでcsでの認証の構成


    認証サービスを追加するには、次のコードをConfigureServicesメソッドに追加します.
    // configure strongly typed settings objects
                var appSettingsSection = Configuration.GetSection("AppSettings");
                services.Configure(appSettingsSection);
    
                // configure jwt authentication
                var appSettings = appSettingsSection.Get();
                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();
                                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に追加します.
    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