Skip to content

Instantly share code, notes, and snippets.

@testfirstcoder
Last active November 1, 2016 08:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save testfirstcoder/95ea7549cef7384fb78dad36a50fbd5b to your computer and use it in GitHub Desktop.
Save testfirstcoder/95ea7549cef7384fb78dad36a50fbd5b to your computer and use it in GitHub Desktop.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using WebApiJwtAuthDemo.Models;
using WebApiJwtAuthDemo.Options;
namespace WebApiJwtAuthDemo.Controllers
{
[Route("api/[controller]")]
public class JwtController : Controller
{
private readonly JwtIssuerOptions _jwtOptions;
private readonly ILogger _logger;
private readonly JsonSerializerSettings _serializerSettings;
public JwtController(IOptions<JwtIssuerOptions> jwtOptions, ILoggerFactory loggerFactory)
{
_jwtOptions = jwtOptions.Value;
ThrowIfInvalidOptions(_jwtOptions);
_logger = loggerFactory.CreateLogger<JwtController>();
_serializerSettings = new JsonSerializerSettings
{
Formatting = Formatting.Indented
};
}
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Get([FromForm] ApplicationUser applicationUser)
{
var identity = await GetClaimsIdentity(applicationUser);
if (identity == null)
{
_logger.LogInformation($"Invalid username ({applicationUser.UserName}) or password ({applicationUser.Password})");
return BadRequest("Invalid credentials");
}
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, applicationUser.UserName),
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
new Claim(JwtRegisteredClaimNames.Iat,
ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(),
ClaimValueTypes.Integer64),
identity.FindFirst("DisneyCharacter")
};
// Create the JWT security token and encode it.
var jwt = new JwtSecurityToken(
issuer: _jwtOptions.Issuer,
audience: _jwtOptions.Audience,
claims: claims,
notBefore: _jwtOptions.NotBefore,
expires: _jwtOptions.Expiration,
signingCredentials: _jwtOptions.SigningCredentials);
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
// Serialize and return the response
var response = new
{
access_token = encodedJwt,
expires_in = (int)_jwtOptions.ValidFor.TotalSeconds
};
var json = JsonConvert.SerializeObject(response, _serializerSettings);
return new OkObjectResult(json);
}
private static void ThrowIfInvalidOptions(JwtIssuerOptions options)
{
if (options == null) throw new ArgumentNullException(nameof(options));
if (options.ValidFor <= TimeSpan.Zero)
{
throw new ArgumentException("Must be a non-zero TimeSpan.", nameof(JwtIssuerOptions.ValidFor));
}
if (options.SigningCredentials == null)
{
throw new ArgumentNullException(nameof(JwtIssuerOptions.SigningCredentials));
}
if (options.JtiGenerator == null)
{
throw new ArgumentNullException(nameof(JwtIssuerOptions.JtiGenerator));
}
}
/// <returns>Date converted to seconds since Unix epoch (Jan 1, 1970, midnight UTC).</returns>
private static long ToUnixEpochDate(DateTime date) => new DateTimeOffset(date).ToUnixTimeSeconds();
/// <summary>
/// IMAGINE BIG RED WARNING SIGNS HERE!
/// You'd want to retrieve claims through your claims provider
/// in whatever way suits you, the below is purely for demo purposes!
/// </summary>
private static Task<ClaimsIdentity> GetClaimsIdentity(ApplicationUser user)
{
if (user.UserName == "MickeyMouse" &&
user.Password == "MickeyMouseIsBoss123")
{
return Task.FromResult(new ClaimsIdentity(
new GenericIdentity(user.UserName, "Token"),
new[]
{
new Claim("DisneyCharacter", "IAmMickey")
}));
}
if (user.UserName == "NotMickeyMouse" &&
user.Password == "MickeyMouseIsBoss123")
{
return Task.FromResult(new ClaimsIdentity(
new GenericIdentity(user.UserName, "Token"),
new Claim[] { }));
}
// Credentials are invalid, or account doesn't exist
return Task.FromResult<ClaimsIdentity>(null);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment