ASP.NET Core Web API
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Principal;
namespace Jwt.Controllers
{
[Produces("application/json")]
[Route("api/Token")]
public class TokenController : Controller
{
private readonly TokenAuthOptions tokenOptions;
public TokenController(TokenAuthOptions tokenOptions)
{
this.tokenOptions = tokenOptions;
//this.bearerOptions = options.Value;
//this.signingCredentials = signingCredentials;
}
/// <summary>
/// Check if currently authenticated. Will throw an exception of some sort which should be caught by a general
/// exception handler and returned to the user as a 401, if not authenticated. Will return a fresh token if
/// the user is authenticated, which will reset the expiry.
/// </summary>
/// <returns></returns>
[HttpGet]
[Authorize("Bearer")]
public dynamic Get()
{
/*
******* WARNING WARNING WARNING ******
******* WARNING WARNING WARNING ******
******* WARNING WARNING WARNING ******
THIS METHOD ALLOWS A USER WITH A VALID TOKEN TO REMAIN LOGGED IN
FOREVER, WITH NO WAY OF EVER EXPIRING THEIR RIGHT TO USE THE
APPLICATION. Consider whether this is appropriate for your
application's needs.
Refresh Tokens (see https://auth0.com/docs/refresh-token) could be used to
retrieve new tokens.
******* WARNING WARNING WARNING ******
******* WARNING WARNING WARNING ******
******* WARNING WARNING WARNING ******
*/
bool authenticated = false;
string user = null;
int entityId = -1;
string token = null;
DateTime? tokenExpires = default(DateTime?);
var currentUser = HttpContext.User;
if (currentUser != null)
{
authenticated = currentUser.Identity.IsAuthenticated;
if (authenticated)
{
user = currentUser.Identity.Name;
foreach (Claim c in currentUser.Claims) if (c.Type == "EntityID") entityId = Convert.ToInt32(c.Value);
tokenExpires = DateTime.UtcNow.AddMinutes(2);
token = GetToken(currentUser.Identity.Name, tokenExpires);
}
}
return new { authenticated = authenticated, user = user, entityId = entityId, token = token, tokenExpires = tokenExpires };
}
public class AuthRequest
{
public string username { get; set; }
public string password { get; set; }
}
/// <summary>
/// Request a new token for a given username/password pair.
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
[HttpPost]
[AllowAnonymous]
public dynamic Post([FromBody] AuthRequest req)
{
// Obviously, at this point you need to validate the username and password against whatever system you wish.
if ((req.username == "TEST" && req.password == "TEST") || (req.username == "TEST2" && req.password == "TEST"))
{
DateTime? expires = DateTime.UtcNow.AddDays(1);
var token = GetToken(req.username, expires);
return new { authenticated = true, entityId = 1, token = token, tokenExpires = expires };
}
return new { authenticated = false };
}
private string GetToken(string user, DateTime? expires)
{
var handler = new JwtSecurityTokenHandler();
// Here, you should create or look up an identity for the user which is being authenticated.
// For now, just creating a simple generic identity.
ClaimsIdentity identity = new ClaimsIdentity(new GenericIdentity(user, "TokenAuth"), new[] { new Claim("EntityID", "1", ClaimValueTypes.Integer) });
var securityToken = handler.CreateToken(new Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor()
{
Issuer = tokenOptions.Issuer,
Audience = tokenOptions.Audience,
SigningCredentials = tokenOptions.SigningCredentials,
Subject = identity,
Expires = expires
});
return handler.WriteToken(securityToken);
}
}
}
HTML
<!DOCTYPE html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Index</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- <link rel="manifest" href="site.webmanifest"> -->
<!-- <link rel="apple-touch-icon" href="icon.png"> -->
<!-- Place favicon.ico in the root directory -->
<!-- <link rel="stylesheet" href="css/main.css"> -->
<!-- Custom styles for signin page -->
<link href="css/account/signin.css" rel="stylesheet" />
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!-- Latest compiled JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/locale/vi.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.13/moment-timezone.min.js"></script>
<script>
$(document).ready(function () {
// DOM ready
// Test data
/*
* To test the script you should discomment the function
* testLocalStorageData and refresh the page. The function
* will load some test data and the loadProfile
* will do the changes in the UI
*/
// testLocalStorageData();
// Load profile if it exits
loadProfile();
});
/**
* Function that gets the data of the profile in case
* thar it has already saved in localstorage. Only the
* UI will be update in case that all data is available
*
* A not existing key in localstorage return null
*
*/
function getLocalProfile(callback) {
var profileImgSrc = localStorage.getItem("PROFILE_IMG_SRC");
var profileName = localStorage.getItem("PROFILE_NAME");
var profileReAuthEmail = localStorage.getItem("PROFILE_REAUTH_EMAIL");
if (profileName !== null
&& profileReAuthEmail !== null
&& profileImgSrc !== null) {
callback(profileImgSrc, profileName, profileReAuthEmail);
}
}
/**
* Main function that load the profile if exists
* in localstorage
*/
function loadProfile() {
if (!supportsHTML5Storage()) { return false; }
// we have to provide to the callback the basic
// information to set the profile
getLocalProfile(function (profileImgSrc, profileName, profileReAuthEmail) {
//changes in the UI
$("#profile-img").attr("src", profileImgSrc);
$("#profile-name").html(profileName);
$("#reauth-email").html(profileReAuthEmail);
$("#inputEmail").hide();
$("#remember").hide();
});
}
/**
* function that checks if the browser supports HTML5
* local storage
*
* @returns {boolean}
*/
function supportsHTML5Storage() {
try {
return 'localStorage' in window && window['localStorage'] !== null;
} catch (e) {
return false;
}
}
/**
* Test data. This data will be safe by the web app
* in the first successful login of a auth user.
* To Test the scripts, delete the localstorage data
* and comment this call.
*
* @returns {boolean}
*/
function testLocalStorageData() {
if (!supportsHTML5Storage()) { return false; }
localStorage.setItem("PROFILE_IMG_SRC", "//lh3.googleusercontent.com/-6V8xOA6M7BA/AAAAAAAAAAI/AAAAAAAAAAA/rzlHcD0KYwo/photo.jpg?sz=120");
localStorage.setItem("PROFILE_NAME", "César Izquierdo Tello");
localStorage.setItem("PROFILE_REAUTH_EMAIL", "oneaccount@gmail.com");
}
window.onload = function window_onload() {
console.log('onload');
}
</script>
</head>
<body class="page-bootstrap4 Alpha">
<!--[if lte IE 9]>
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="https://browsehappy.com/">upgrade your browser</a> to improve your experience and security.</p>
<![endif]-->
<!-- Add your site or application content here -->
<!--
you can substitue the span of reauth email for a input with the email and
include the remember me checkbox
-->
<div class="container">
<div class="card card-container">
<!-- <img class="profile-img-card" src="//lh3.googleusercontent.com/-6V8xOA6M7BA/AAAAAAAAAAI/AAAAAAAAAAA/rzlHcD0KYwo/photo.jpg?sz=120" alt="" /> -->
<img id="profile-img" class="profile-img-card" src="//ssl.gstatic.com/accounts/ui/avatar_2x.png" />
<p id="profile-name" class="profile-name-card"></p>
<form class="form-signin" action="api/Token" method="post" id="formSignin">
<span id="reauth-email" class="reauth-email"></span>
<input type="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus>
<input type="password" id="inputPassword" class="form-control" placeholder="Password" required>
<div id="remember" class="checkbox">
<label>
<input type="checkbox" value="remember-me" id="checkboxRemember"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block btn-signin" type="submit">Sign in</button>
</form><!-- /form -->
<a href="#" class="forgot-password">
Forgot the password?
</a>
</div><!-- /card-container -->
</div><!-- /container -->
<script>
$(function () {
$('#formSignin').submit(function (e) {
e.preventDefault();
var username = $('#inputEmail').val();
var password = $('#inputPassword').val();
var rememberme = $('#checkboxRemember').prop('checked');
var urlSignin = $(this).prop('action');
$.ajax({
type: "POST",
url: urlSignin,
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify({
username: "TEST",
password: "TEST"
}),
success: function (data) {
if (data.authenticated) {
console.log(data.token);
}
},
error: function (error) {
console.log(error);
}
});
});
});
</script>
</body>
</html>
Notes
+ The MIME media type for JSON text is application/json. The default encoding is UTF-8.
+ The MIME types can learn at below link
https://github.com/h5bp/server-configs-nginx/blob/master/mime.types