使用ipasswordhasher<用户>和bcrypt algorhitm

发布于 2025-02-10 10:27:42 字数 7291 浏览 1 评论 0原文

我在ASP.NET中遇到了哈希,盐和验证密码的问题。 我正在创建一个新用户,然后使用哈希方法。 但是,当我尝试获得一些需要授权的资源时,我 输入与我保存在数据库中的相同用户名和密码失败。

这是我的密码HASHER类:

using Microsoft.AspNetCore.Identity;

namespace FlowerShop.ApplicationServices.Components.PasswordHasher
{
    public class BCryptPasswordHasher<User> : IPasswordHasher<User> where User : class
{
    
    public string HashPassword(User user, string password)
    {  
        return BCrypt.Net.BCrypt.HashPassword(password, 12);
    }

    public PasswordVerificationResult VerifyHashedPassword(User user, string hashedPassword, string providedPassword)
    {
        var isValid = BCrypt.Net.BCrypt.Verify(providedPassword, hashedPassword);

        if (isValid && BCrypt.Net.BCrypt.PasswordNeedsRehash(hashedPassword, 12))
        {
            return PasswordVerificationResult.SuccessRehashNeeded;
        }

        return isValid ? PasswordVerificationResult.Success : PasswordVerificationResult.Failed;
    }
}

这是我的身份验证类:

public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    private readonly IQueryExecutor queryExecutor;
    private readonly IPasswordHasher<User> passwordHasher;

    public BasicAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, 
        ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, 
        IQueryExecutor queryExecutor, IPasswordHasher<User> passwordHasher)
        : base(options, logger, encoder, clock)
    {
        this.queryExecutor = queryExecutor;
        this.passwordHasher = passwordHasher;
    }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        var endpoint = Context.GetEndpoint();
        if (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null)
        {
            return AuthenticateResult.NoResult();
        }

        if (!Request.Headers.ContainsKey("Authorization"))
        {
            return AuthenticateResult.Fail("Missing Authorization Header");
        }

        User user = null;

        try
        {
            var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
            var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
            var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
            var username = credentials[0];
            var providedPassword = passwordHasher.HashPassword(user, credentials[1]);

            var query = new GetUserQuery()
            {
                UserName = username
            };
            user = await this.queryExecutor.Execute(query);
                           
            if (user == null || passwordHasher.VerifyHashedPassword(user, user.PasswordHash, providedPassword) 
                == PasswordVerificationResult.Failed)
            {
                return AuthenticateResult.Fail("Invalid Authorization Header");
            }
        }
        catch
        {
            return AuthenticateResult.Fail("Invalid Authorization Header");
        }

        var claims = new[]
        {
            new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
            new Claim(ClaimTypes.Name, user.UserName),
            new Claim(ClaimTypes.Role, user.Role.ToString()),
            new Claim(ClaimTypes.Email, user.Email),
        };
        var identity = new ClaimsIdentity(claims, Scheme.Name);
        var principal = new ClaimsPrincipal(identity);
        var ticket = new AuthenticationTicket(principal, Scheme.Name);
        
        return AuthenticateResult.Success(ticket);
    }
}

在这个地方,我正在创建一个新用户:

        using MediatR;
        using Microsoft.AspNetCore.Identity;
        using System.Threading;
        using System.Threading.Tasks;

        public class AddUserHandler : IRequestHandler<AddUserRequest,
    AddUserResponse>
        {
        private readonly ICommandExecutor commandExecutor;
        private readonly IQueryExecutor queryExecutor;
        private readonly IMapper mapper;
        private readonly IPasswordHasher<User> passwordHasher;

            public AddUserHandler(ICommandExecutor commandExecutor,
    IQueryExecutor queryExecutor, 
                IMapper mapper, IPasswordHasher<User> passwordHasher)
            {
                this.commandExecutor = commandExecutor;
                this.queryExecutor = queryExecutor;
                this.mapper = mapper;
                this.passwordHasher = passwordHasher;
            }

            public async Task<AddUserResponse> Handle(AddUserRequest
    request, CancellationToken cancellationToken)
            {
            var query = new GetUserQuery()
            {                
                UserName = request.UserName,
                Email = request.Email
            };

            var getUser = await this.queryExecutor.Execute(query);
            if (getUser != null)
            {
                if (getUser.UserName == request.UserName)      

              {
                        return new AddUserResponse()
                        {
                            Error = new ErrorModel(ErrorType.ValidationError +
    "! The name is already taken.")
                        };
                    }
                if (getUser.Email == request.Email)
                {
         

               return new AddUserResponse()
                        {
                            Error = new ErrorModel(ErrorType.ValidationError +
    "! Email address is in use.")
                        };
                    }
                return new AddUserResponse()
                {
                    Error = new ErrorModel(ErrorType.Conflict)
                };
            }

            request.PasswordHash = passwordHasher.HashPassword(getUser,
request.Password);

            var user = this.mapper.Map<User>(request);
            var command = new AddUserCommand() 
            { 
                Parameter = user 
            };
            var addedUser = await this.commandExecutor.Execute(command);
            var response = new AddUserResponse()
            {
                Data =
this.mapper.Map<Domain.Models.UserDTO>(addedUser)
            };

            return response;
        }
    }

这是我的startup.cs:

      public void ConfigureServices(IServiceCollection services)
            {
                services.AddAuthentication("BasicAuthentication")
                        .AddScheme<AuthenticationSchemeOptions,
    BasicAuthenticationHandler>("BasicAuthentication", null);
    
                services.AddScoped<IPasswordHasher<User>,
    BCryptPasswordHasher<User>>();
}

也许首先,是否正确实现了?

  1. 在Adduserhandler中,Hash正确分配给request.passwordhash吗?
  2. 如何检索盐并分配request.passwordsalt? 对不起,如果发生任何不清楚的事情。

任何反馈和帮助将不胜感激。

预先感谢:)

编辑:

例如,如果我添加了密码“ pass123”的用户,并且将其存储在'user.passwordhash =“ $ 2A $ 2A $ 12 $ 12 $ iqpy7fyqh/pt2o8epttg5eoqkzo1v395wrndaxppppppppppppppp5qf.nq.kxuyy and hish inships hish hish hish inships in 'supplypassword =“ $ 2A $ 12 $ 9VSZ8SW/wtmqgy6jyditlen/btz0wxjkxdob3sdpanviidgbpaqt。”''

I faced problem with hashing, salting and verifying password in ASP.NET.
I am creating a new User and then using hashing method.
But when I try to get some resources which requires Authorization and I
enter the same username and password as I saved in database the result is failed.

Here is my password hasher class:

using Microsoft.AspNetCore.Identity;

namespace FlowerShop.ApplicationServices.Components.PasswordHasher
{
    public class BCryptPasswordHasher<User> : IPasswordHasher<User> where User : class
{
    
    public string HashPassword(User user, string password)
    {  
        return BCrypt.Net.BCrypt.HashPassword(password, 12);
    }

    public PasswordVerificationResult VerifyHashedPassword(User user, string hashedPassword, string providedPassword)
    {
        var isValid = BCrypt.Net.BCrypt.Verify(providedPassword, hashedPassword);

        if (isValid && BCrypt.Net.BCrypt.PasswordNeedsRehash(hashedPassword, 12))
        {
            return PasswordVerificationResult.SuccessRehashNeeded;
        }

        return isValid ? PasswordVerificationResult.Success : PasswordVerificationResult.Failed;
    }
}

This is my authentication class:

public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    private readonly IQueryExecutor queryExecutor;
    private readonly IPasswordHasher<User> passwordHasher;

    public BasicAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, 
        ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, 
        IQueryExecutor queryExecutor, IPasswordHasher<User> passwordHasher)
        : base(options, logger, encoder, clock)
    {
        this.queryExecutor = queryExecutor;
        this.passwordHasher = passwordHasher;
    }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        var endpoint = Context.GetEndpoint();
        if (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null)
        {
            return AuthenticateResult.NoResult();
        }

        if (!Request.Headers.ContainsKey("Authorization"))
        {
            return AuthenticateResult.Fail("Missing Authorization Header");
        }

        User user = null;

        try
        {
            var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
            var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
            var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
            var username = credentials[0];
            var providedPassword = passwordHasher.HashPassword(user, credentials[1]);

            var query = new GetUserQuery()
            {
                UserName = username
            };
            user = await this.queryExecutor.Execute(query);
                           
            if (user == null || passwordHasher.VerifyHashedPassword(user, user.PasswordHash, providedPassword) 
                == PasswordVerificationResult.Failed)
            {
                return AuthenticateResult.Fail("Invalid Authorization Header");
            }
        }
        catch
        {
            return AuthenticateResult.Fail("Invalid Authorization Header");
        }

        var claims = new[]
        {
            new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
            new Claim(ClaimTypes.Name, user.UserName),
            new Claim(ClaimTypes.Role, user.Role.ToString()),
            new Claim(ClaimTypes.Email, user.Email),
        };
        var identity = new ClaimsIdentity(claims, Scheme.Name);
        var principal = new ClaimsPrincipal(identity);
        var ticket = new AuthenticationTicket(principal, Scheme.Name);
        
        return AuthenticateResult.Success(ticket);
    }
}

And in this place I am creating a new User:

        using MediatR;
        using Microsoft.AspNetCore.Identity;
        using System.Threading;
        using System.Threading.Tasks;

        public class AddUserHandler : IRequestHandler<AddUserRequest,
    AddUserResponse>
        {
        private readonly ICommandExecutor commandExecutor;
        private readonly IQueryExecutor queryExecutor;
        private readonly IMapper mapper;
        private readonly IPasswordHasher<User> passwordHasher;

            public AddUserHandler(ICommandExecutor commandExecutor,
    IQueryExecutor queryExecutor, 
                IMapper mapper, IPasswordHasher<User> passwordHasher)
            {
                this.commandExecutor = commandExecutor;
                this.queryExecutor = queryExecutor;
                this.mapper = mapper;
                this.passwordHasher = passwordHasher;
            }

            public async Task<AddUserResponse> Handle(AddUserRequest
    request, CancellationToken cancellationToken)
            {
            var query = new GetUserQuery()
            {                
                UserName = request.UserName,
                Email = request.Email
            };

            var getUser = await this.queryExecutor.Execute(query);
            if (getUser != null)
            {
                if (getUser.UserName == request.UserName)      

              {
                        return new AddUserResponse()
                        {
                            Error = new ErrorModel(ErrorType.ValidationError +
    "! The name is already taken.")
                        };
                    }
                if (getUser.Email == request.Email)
                {
         

               return new AddUserResponse()
                        {
                            Error = new ErrorModel(ErrorType.ValidationError +
    "! Email address is in use.")
                        };
                    }
                return new AddUserResponse()
                {
                    Error = new ErrorModel(ErrorType.Conflict)
                };
            }

            request.PasswordHash = passwordHasher.HashPassword(getUser,
request.Password);

            var user = this.mapper.Map<User>(request);
            var command = new AddUserCommand() 
            { 
                Parameter = user 
            };
            var addedUser = await this.commandExecutor.Execute(command);
            var response = new AddUserResponse()
            {
                Data =
this.mapper.Map<Domain.Models.UserDTO>(addedUser)
            };

            return response;
        }
    }

This is my Startup.cs :

      public void ConfigureServices(IServiceCollection services)
            {
                services.AddAuthentication("BasicAuthentication")
                        .AddScheme<AuthenticationSchemeOptions,
    BasicAuthenticationHandler>("BasicAuthentication", null);
    
                services.AddScoped<IPasswordHasher<User>,
    BCryptPasswordHasher<User>>();
}

Maybe first of all, is it all correct implemented?

  1. Is hash in AddUserHandler correct assigned to request.PasswordHash?
  2. How to retrieve salt and assign to request.PasswordSalt?
    Sorry for any unclear things if they occur.

Any feedback and help will be appreciated.

Thanks in advance :)

Edit:

for example if I add user with password "pass123" and it is stored in database as 'user.PasswordHash = "$2a$12$Iqpy7FyQh/pt2O8upTtG5eOQKzo1V395wRNdAXPpp5Qf.NQ.KxUyy"' and provided password after hashing is 'providedPassword = "$2a$12$9vSz8Sw/WtmqGY6jyDiTleN/btZ0wXJkXdoB3sDpANVIIDGBpaqT."'

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

┈┾☆殇 2025-02-17 10:27:42

如果有人在未来需要使用它,我将其修复了错误。
问题在于我的身份验证课。
代替:

var username = credentials[0];
var providedPassword = passwordHasher.HashPassword(user, credentials[1]);

应该是:

var username = credentials[0];
var providedPassword = credentials[1];

我确定我已经检查了几次,但是以某种方式无法使用。无论如何,它最终正常工作。

I fixed the bug if anyone needs to use it in thee future.
The problem was in my authentication class.
In place of:

var username = credentials[0];
var providedPassword = passwordHasher.HashPassword(user, credentials[1]);

Should be:

var username = credentials[0];
var providedPassword = credentials[1];

I am sure that I have checked it a few times but somehow didn't work then. Anyway, it finally works properly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文