7

ASP.NET Core 5 with ASP.NET Identity 3.0, I'm using both web pages and apis. I am using OpenIddict to issue a JWT token and to authenticate. My code looks as such:

    X509Certificate2 c = new X509Certificate2(@"tokensign.p12", "MyCertificatePassword");

    services.AddOpenIddict<WebUser, IdentityRole<int>, WebDbContext, int>()
        .EnableTokenEndpoint("/api/customauth/login")
        .AllowPasswordFlow()
        .UseJsonWebTokens()
        .AddSigningCertificate(c);

If I disable UseJsonWebTokens(), I can generate a token and authorise successfully. However, I am not sure that my certificate is validating the returned tokens.

And when enable UseJsonWebTokens, I am able to issue a JWT token at this end point. However, I can't authenticate any request!

I am using the following code in the app configuration:

    app.UseJwtBearerAuthentication(new JwtBearerOptions
    {
        AutomaticAuthenticate = true,
        AutomaticChallenge = true,
        RequireHttpsMetadata = false,
        Authority = "http://localhost:60000/",
        Audience = "http://localhost:60000/",
    });
    app.UseOAuthValidation();
    app.UseIdentity();
    app.UseOpenIddict();
    app.UseMvcWithDefaultRoute();
  • How can I enforce the request to be validated with my certificate to make sure the JWT token is not tampered with.
  • What are the correct settings that will allow validation and authorisation of my JWT token, given that if I am not using JWT, I am getting authorised successfully.
4

2 回答 2

6

If I disable UseJsonWebTokens(), I can generate a token and authorise successfully. However, I am not sure that my certificate is validating the returned tokens.

In ASOS (the OpenID Connect server framework behind OpenIddict), there are 2 different built-in serialization mechanisms to create and protect tokens:

  • One that uses IdentityModel (a library developed by Microsoft) and produces standard tokens verifiable by third parties:

Identity tokens (JWT by definition) are always created using this process and you can call UseJsonWebTokens() to force OpenIddict to issue access tokens that use the same serialization process.

The certificate you specify when calling AddSigningCertificate() is always used to sign these tokens.

  • One that uses the ASP.NET Core Data Protection stack (also developed by Microsoft):

This stack exclusively produces "proprietary" tokens that are not meant to be read or verified by a third-party, as the token format is not standard and necessarily relies on symmetric signing and encryption.

It's the mechanism we use for authorization codes and refresh tokens, that are only meant to be consumed by OpenIddict itself. It's also used for access tokens when you use the default token format.

In this case, the certificate you specify when calling AddSigningCertificate() is not used.

Instead, these tokens are always encrypted by the Data Protection stack using an Authenticated Encryption algorithm (by default, AES-256-CBC with HMACSHA256), that provides authenticity, integrity and confidentiality. For that, 2 keys (one for encryption, one for validation) are derived by the Data Protection stack from one of the master keys stored in the key ring.

How can I enforce the request to be validated with my certificate to make sure the JWT token is not tampered with. What are the correct settings that will allow validation and authorisation of my JWT token, given that if I am not using JWT, I am getting authorised successfully.

To answer these questions, it would help if you enabled logging and shared your traces.

于 2016-07-23T12:58:35.417 回答
0

Creating JWT Token based authentication in ASP.NET Core is very very simple. Please follow below link you will get more idea. How to Create JWT Token in Asp NET Core

Sample Code

public static class AuthenticationConfig
{
    public static string GenerateJSONWebToken(string user)
    {
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("730F046B1ADF1555FF0C80149B47B38CD7C0A146AAFA34870E863CAA25B585C3"));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var claims = new[] {
             new Claim("UserName", user),
              new Claim("Role", "1"),
                };

        var token = new JwtSecurityToken("http://localhost:30972",
          "http://localhost:30972",
          claims,
          DateTime.UtcNow,
          expires: DateTime.Now.AddMinutes(10),
          signingCredentials: credentials);

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

    //ConfigureJwtAuthentication
    internal static TokenValidationParameters tokenValidationParams;
    public static void ConfigureJwtAuthentication(this IServiceCollection services)
    {
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("730F046B1ADF1555FF0C80149B47B38CD7C0A146AAFA34870E863CAA25B585C3"));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        tokenValidationParams = new TokenValidationParameters()
        {
            ValidateIssuerSigningKey = true,
            ValidIssuer = "http://localhost:30972",
            ValidateLifetime = true,
            ValidAudience = "http://localhost:30972",
            ValidateAudience = true,
            RequireSignedTokens = true,
            // Use our signing credentials key here
            // optionally we can inject an RSA key as
            //IssuerSigningKey = new RsaSecurityKey(rsaParams),
            IssuerSigningKey = credentials.Key,
            ClockSkew = TimeSpan.FromMinutes(10)
        };
        services.AddAuthentication(options =>
        {
            options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        })

        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = tokenValidationParams;
            #if PROD || UAT
                  options.IncludeErrorDetails = false;
            #elif DEBUG
                  options.RequireHttpsMetadata = false;
            #endif
        });
    }
}

Add this line in Startup.cs

 public void ConfigureServices(IServiceCollection services)
    {
        services.ConfigureJwtAuthentication();
        services.AddAuthorization(options =>
        {
            options.DefaultPolicy = new  AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme).RequireAuthenticatedUser().Build();
        });
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

Add these lines in Authentication Controller

[Route("api/[controller]")]
public class AuthenticationController : Controller
{
    // GET: api/<controller>
    [HttpGet]
    public string Get(string user, string pass)
    {
        if (user == "admin")
        {
            return AuthenticationConfig.GenerateJSONWebToken(user);
        }
        else
        {
            return "";
        }

    }


    // POST api/<controller>
    [Authorize]
    [HttpPost]
    public string Post()
    {
        var identity = HttpContext.User.Identity as ClaimsIdentity;
        IEnumerable<Claim> claim = identity.Claims;
        var UserName = claim.Where(c => c.Type == "UserName").Select(c => c.Value).SingleOrDefault();

        return "Welcome to " + UserName + "!";
    }


}
于 2019-08-12T04:03:50.183 回答