gpt4 book ai didi

没有身份的 ASP.NET Core 2.0 承载身份验证

转载 作者:行者123 更新时间:2023-12-03 10:26:16 25 4
gpt4 key购买 nike

当我一天前开始在 .NET core 2.0 上实现一个独立的承载身份验证 webapi 时,我以为我有一个非常简单的目标,但我还没有让任何远程工作。这是我正在尝试做的事情的列表:

  • 实现不记名 token 保护的 webapi
  • 从同一项目中的端点发出 token 和刷新 token
  • 使用 [Authorize] 属性控制对 api 表面的访问
  • 不使用 ASP.Net 身份(我的用户/成员(member)资格要求更轻)

  • 我完全可以在登录中构建身份/声明/主体并将其添加到请求上下文中,但我还没有看到一个关于如何在没有身份的 Core 2.0 webapi 中发布和使用身份验证/刷新 token 的示例。我已经看过没有身份的 1.x MSDN cookie 示例,但这并没有让我理解到足以满足上述要求。

    我觉得这可能是一个常见的场景,它不应该这么难(也许不是,也许只是缺乏文档/示例?)。据我所知,IdentityServer4 与 Core 2.0 Auth 不兼容,opendiddict 似乎需要 Identity。我也不想在单独的进程中托管 token 端点,而是在同一个 webapi 实例中。

    谁能指出一个具体的例子,或者至少就最佳步骤/选项提供一些指导?

    最佳答案

    进行了编辑以使其与 ASP.NET Core 2.0 兼容。

    首先,一些 Nuget 包:

  • Microsoft.AspNetCore.Authentication.JwtBearer
  • Microsoft.AspNetCore.Identity
  • System.IdentityModel.Tokens.Jwt
  • System.Security.Cryptography.Csp

  • 然后是一些基本的数据传输对象。
    // Presumably you will have an equivalent user account class with a user name.
    public class User
    {
    public string UserName { get; set; }
    }

    public class JsonWebToken
    {
    public string access_token { get; set; }

    public string token_type { get; set; } = "bearer";

    public int expires_in { get; set; }

    public string refresh_token { get; set; }
    }

    进入正确的功能,您将需要一个登录/ token Web 方法来实际将授权 token 发送给用户。
    [Route("api/token")]
    public class TokenController : Controller
    {
    private ITokenProvider _tokenProvider;

    public TokenController(ITokenProvider tokenProvider) // We'll create this later, don't worry.
    {
    _tokenProvider = tokenProvider;
    }

    public JsonWebToken Get([FromQuery] string grant_type, [FromQuery] string username, [FromQuery] string password, [FromQuery] string refresh_token)
    {
    // Authenticate depending on the grant type.
    User user = grant_type == "refresh_token" ? GetUserByToken(refresh_token) : GetUserByCredentials(username, password);

    if (user == null)
    throw new UnauthorizedAccessException("No!");

    int ageInMinutes = 20; // However long you want...

    DateTime expiry = DateTime.UtcNow.AddMinutes(ageInMinutes);

    var token = new JsonWebToken {
    access_token = _tokenProvider.CreateToken(user, expiry),
    expires_in = ageInMinutes * 60
    };

    if (grant_type != "refresh_token")
    token.refresh_token = GenerateRefreshToken(user);

    return token;
    }

    private User GetUserByToken(string refreshToken)
    {
    // TODO: Check token against your database.
    if (refreshToken == "test")
    return new User { UserName = "test" };

    return null;
    }

    private User GetUserByCredentials(string username, string password)
    {
    // TODO: Check username/password against your database.
    if (username == password)
    return new User { UserName = username };

    return null;
    }

    private string GenerateRefreshToken(User user)
    {
    // TODO: Create and persist a refresh token.
    return "test";
    }
    }

    您可能注意到 token 创建仍然只是由一些虚构的 ITokenProvider 传递的“魔法”。定义 token 提供者接口(interface)。
    public interface ITokenProvider
    {
    string CreateToken(User user, DateTime expiry);

    // TokenValidationParameters is from Microsoft.IdentityModel.Tokens
    TokenValidationParameters GetValidationParameters();
    }

    我在 JWT 上使用 RSA 安全 key 实现了 token 创建。所以...
    public class RsaJwtTokenProvider : ITokenProvider
    {
    private RsaSecurityKey _key;
    private string _algorithm;
    private string _issuer;
    private string _audience;

    public RsaJwtTokenProvider(string issuer, string audience, string keyName)
    {
    var parameters = new CspParameters { KeyContainerName = keyName };
    var provider = new RSACryptoServiceProvider(2048, parameters);

    _key = new RsaSecurityKey(provider);

    _algorithm = SecurityAlgorithms.RsaSha256Signature;
    _issuer = issuer;
    _audience = audience;
    }

    public string CreateToken(User user, DateTime expiry)
    {
    JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();

    ClaimsIdentity identity = new ClaimsIdentity(new GenericIdentity(user.UserName, "jwt"));

    // TODO: Add whatever claims the user may have...

    SecurityToken token = tokenHandler.CreateJwtSecurityToken(new SecurityTokenDescriptor
    {
    Audience = _audience,
    Issuer = _issuer,
    SigningCredentials = new SigningCredentials(_key, _algorithm),
    Expires = expiry.ToUniversalTime(),
    Subject = identity
    });

    return tokenHandler.WriteToken(token);
    }

    public TokenValidationParameters GetValidationParameters()
    {
    return new TokenValidationParameters
    {
    IssuerSigningKey = _key,
    ValidAudience = _audience,
    ValidIssuer = _issuer,
    ValidateLifetime = true,
    ClockSkew = TimeSpan.FromSeconds(0) // Identity and resource servers are the same.
    };
    }
    }

    所以你现在正在生成 token 。是时候实际验证它们并将其连接起来了。转到您的 Startup.cs。

    ConfigureServices()
    var tokenProvider = new RsaJwtTokenProvider("issuer", "audience", "mykeyname");
    services.AddSingleton<ITokenProvider>(tokenProvider);

    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options => {
    options.RequireHttpsMetadata = false;
    options.TokenValidationParameters = tokenProvider.GetValidationParameters();
    });

    // This is for the [Authorize] attributes.
    services.AddAuthorization(auth => {
    auth.DefaultPolicy = new AuthorizationPolicyBuilder()
    .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
    .RequireAuthenticatedUser()
    .Build();
    });

    然后 Configure()
    public void Configure(IApplicationBuilder app)
    {
    app.UseAuthentication();

    // Whatever else you're putting in here...

    app.UseMvc();
    }

    这应该是你所需要的。希望我没有错过任何东西。

    幸福的结果是……
    [Authorize] // Yay!
    [Route("api/values")]
    public class ValuesController : Controller
    {
    // ...
    }

    关于没有身份的 ASP.NET Core 2.0 承载身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45715394/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com