【问题标题】:How to make secure authentication for .NET Core Web API?如何为 .NET Core Web API 进行安全身份验证?
【发布时间】:2020-11-15 14:47:57
【问题描述】:

我正在使用 .NET Core Web API、Entity Framework 和 React 开发一个应用程序。我最近一直在阅读很多关于我的 API 可能的身份验证技术的文章,我发现普通 JWT 并不完全安全,所以起初我决定将 OpenID Connect 与 IdentityServer 4 一起使用。我了解 OAuth 2.0 和 OpenID 背后的想法Connect 是在登录过程中隐藏用户凭据,并让外部身份验证提供商参与发布访问令牌,但我不想依赖此类服务,因为并非每个人都在 Facebook 等上拥有帐户。我认为这是一种可选方式登录。我想让用户只需登录名和密码即可登录。那么在现代网络应用中实现这一目标的最佳(安全)方式是什么?

将项目 1 作为客户端应用程序,将项目 2 作为 API 资源,将项目 3 作为授权服务 (IdentityServer4),我考虑以下场景:

  1. 用户可以在授权服务上创建一个帐户,该帐户负责颁发通过客户端应用程序访问 API 资源所需的令牌。授权服务仅注册为我的客户端应用程序的授权提供者。

  2. 使用资源所有者密码授权从授权服务获取授权令牌 - 规范不推荐使用此令牌,但在我的情况下,因为用户必须向授权服务提供凭据,并且我将托管每个项目,我看不到任何问题.

  3. 不用担心 OAuth 并使用 ASP.NET Core Identity + Bearer token 身份验证来实现授权机制。

高度赞赏的任何想法或建议。

【问题讨论】:

  • 也许我的回答here 有用。

标签: oauth-2.0 jwt asp.net-core-webapi identityserver4 openid-connect


【解决方案1】:

我使用 JwtBearer 包,将其连接到您的 Startup.cs 配置方法中,例如

                .UseJwtBearerAuthentication(new JwtBearerOptions
                {
                    AutomaticAuthenticate = true,
                    AutomaticChallenge = true,
                    TokenValidationParameters = new TokenValidationParameters
                    {
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration["AppSettings:AuthConfig:SecretKey"])),
                        ValidateIssuer = true,
                        ValidIssuer = Configuration["AppSettings:AuthConfig:Issuer"],

                        ValidateAudience = true,
                        ValidAudience = Configuration["AppSettings:AuthConfig:Audience"],

                        ValidateLifetime = true,
                    }
                })

我的用户控制器上的登录操作看起来像

        [HttpPost]
        public string Post([FromBody]LoginRequest request)
        {
            var contact = dbContext.Contacts.Where(c => c.Active && c.Email == request.Email).Select(c => new { c.Id, c.PasswordHash }).SingleOrDefault();

            if (contact == null || !Security.PasswordHash.ValidatePassword(request.Password, contact.PasswordHash))
            {
                return string.Empty;
            }

            var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(appSettings.AuthConfig.SecretKey));

            var now = DateTime.UtcNow;

            var claims = new Claim[]
            {
                new Claim(JwtRegisteredClaimNames.Sub, contact.Id.ToString()),
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.Now.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
            };

            var jwt = new JwtSecurityToken(
                issuer: appSettings.AuthConfig.Issuer,
                audience: appSettings.AuthConfig.Audience,
                claims: claims,
                notBefore: now,
                expires: now.AddDays(30),
                signingCredentials: new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256));

            jwt.Payload.Add("roles", dbContext.ContactRoles.Where(cr => cr.ContactId == contact.Id).Select(ur => ur.Role.Name).ToArray());

            return new JwtSecurityTokenHandler().WriteToken(jwt);
        }

我在客户端为 Angular 使用 JWT 包,React 可能有类似的东西。

【讨论】:

    猜你喜欢
    • 2020-10-15
    • 2018-08-09
    • 1970-01-01
    • 2017-04-27
    • 1970-01-01
    • 1970-01-01
    • 2017-09-05
    • 2020-09-05
    • 1970-01-01
    相关资源
    最近更新 更多