Last active
March 1, 2016 02:56
-
-
Save gongdo/7e6e6c159db7582b1614 to your computer and use it in GitHub Desktop.
JwtBearerAuthentication in ASP.NET5 RC1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//--------------------------------------------------------- | |
// ...in the Startup.cs... | |
public void ConfigureServices(IServiceCollection services) | |
{ | |
// ... | |
services.AddAuthentication(); | |
services.AddAuthorization(options => | |
{ | |
var bearerPolicy = new AuthorizationPolicyBuilder() | |
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme) | |
.RequireAuthenticatedUser() | |
.Build(); | |
options.AddPolicy( | |
"Bearer", | |
bearerPolicy); | |
}); | |
// prepare the SigningKey for the JwtBearerAuthenticationService. | |
/* it didn't work on the MONO | |
var rsa = Convert.FromBase64String("{your RSA TokenSigningKey encoded by Base64}"); | |
RSACryptoServiceProvider publicAndPrivate = new RSACryptoServiceProvider(); | |
publicAndPrivate.ImportCspBlob(rsa); | |
var parameters = publicAndPrivate.ExportParameters(true); | |
*/ | |
// It works both .NETCore and MONO environment. | |
// You need to provide all RSAParameters as byte array. | |
// To generate a random RSAParameters, see this SO | |
// http://stackoverflow.com/questions/4233663/generate-random-rsa-keys-with-rsacryptoserviceprovider | |
var parameters = new RSAParameters | |
{ | |
D = GetByteArrayFor("d"), | |
DP = GetByteArrayFor("dp"), | |
DQ = GetByteArrayFor("dq"), | |
Exponent = GetByteArrayFor("exponent"), | |
InverseQ = GetByteArrayFor("inverseQ"), | |
Modulus = GetByteArrayFor("modulus"), | |
P = GetByteArrayFor("p"), | |
Q = GetByteArrayFor("q"), | |
}; | |
var securityKey = new RsaSecurityKey(parameters); | |
var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSha256Signature); | |
// register SigningCredential and the service as singleton to keep this example simple. | |
services.AddInstance(signingCredentials); | |
services.AddSingleton<JwtBearerAuthenticationService>(); | |
// Configure JwtBearerOptions | |
services.Configure<JwtBearerOptions>(options => | |
{ | |
options.Audience = "{TokenAudience}"; | |
options.ClaimsIssuer = "{TokenIssuer}"; | |
options.TokenValidationParameters.IssuerSigningKey = securityKey; | |
options.TokenValidationParameters.ValidAudience = "{TokenAudience}"; | |
options.TokenValidationParameters.ValidIssuer = "{TokenIssuer}"; | |
//... additional options, if necessary... | |
}); | |
// ... | |
} | |
public void Configure( | |
IApplicationBuilder app, | |
IHostingEnvironment env, | |
ILoggerFactory loggerFactory, | |
IOptions<JwtBearerOptions> jwtBearerOptions) // <-- retrieves JwtBearerOptions via Configure() Injection | |
{ | |
//... | |
app.UseJwtBearerAuthentication(jwtBearerOptions.Value); | |
//... | |
} | |
//--------------------------------------------------------- | |
// ...in the Controllers... | |
//... | |
[Authorize("Bearer")] | |
[Route("v1/[controller]")] | |
public class MyController : Controller | |
{ | |
[AllowAnonymous] | |
public async Task<IEnumerable<Foo>> Get() | |
{ | |
//... | |
} | |
[Authorize("Bearer", Roles = "TheOne")] | |
public async Task<Foo> Create() | |
{ | |
//... | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class JwtBearerAuthenticationService | |
{ | |
private readonly JwtBearerOptions options; | |
private readonly SigningCredentials signingCredentials; | |
public JwtBearerAuthenticationService(IOptions<JwtBearerOptions> options, SigningCredentials signingCredentials) | |
{ | |
//...store JwtBearerOptions and SigningCredentials | |
this.options = options.Value; | |
this.signingCredentials = signingCredentials; | |
//... | |
} | |
private JwtSecurityTokenHandler GetHandler() | |
{ | |
var handler = options.SecurityTokenValidators?.OfType<JwtSecurityTokenHandler>().FirstOrDefault(); | |
if (handler == null) | |
{ | |
throw new InvalidOperationException("JwtSecurityTokenHandler not found."); | |
} | |
return handler; | |
} | |
// GetToken from the identity you might have. | |
// or, you can pass simple plain calims. | |
public virtual string GetToken(ClaimsIdentity identity, DateTime? expires = null) | |
{ | |
var handler = GetHandler(); | |
var securityToken = handler.CreateJwtSecurityToken(new SecurityTokenDescriptor | |
{ | |
// ...configure descriptor... | |
Audience = options.TokenValidationParameters.ValidAudience, | |
Claims = GetIssuingClaims(identity), | |
Expires = expires, | |
Issuer = options.TokenValidationParameters.ValidIssuer, | |
SigningCredentials = this.signingCredentials | |
}); | |
return handler.WriteToken(securityToken); | |
} | |
private IEnumerable<Claim> GetIssuingClaims(ClaimsIdentity identity) | |
{ | |
// claim types you want to copy from the given identity | |
var claimTypesToKeep = new[] | |
{ | |
System.Security.Claims.ClaimTypes.Name, | |
System.Security.Claims.ClaimTypes.NameIdentifier, | |
System.Security.Claims.ClaimTypes.Role, | |
}; | |
return identity.Claims | |
.Where(claim => claimTypesToKeep.Contains(claim.Type)); | |
} | |
public virtual ClaimsPrincipal ValidateAccessToken(string accessToken) | |
{ | |
var handler = GetHandler(); | |
SecurityToken securityToken; | |
var principal = handler.ValidateToken(accessToken, options.TokenValidationParameters, out securityToken); | |
// further validation for securityToken... | |
//... | |
return principal; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment