Implement a Token base Identity Authentication instance in ASP. NET Core, coretoken

Source: Internet
Author: User

Implement a Token base Identity Authentication instance in ASP. NET Core, coretoken

In the past, web-based Identity Authentication was based on cookies and sessions. Before more terminals appeared, there was no problem in doing so. However, in the Web API era, what you need to deal with is not just a browser, but also a variety of clients. In this way, there is a problem that these clients do not know what cookies are. (Cookies are actually tricky for browsers to maintain sessions, but HTTP itself is stateless. The APIS provided by various clients are nothing more than HTTP operations)

Token-based identity authentication is born to cope with such changes. It is more open and secure.

There are many methods to implement Token-based identity authentication, but here we only use the APIS provided by Microsoft.

The following example will show you how to use Microsoft JwtSecurityTokenHandler to complete a beare token-based identity authentication.

Note: This type of article is a Step by step tutorial, so that you do not get dizzy. It makes sense to download the complete code to analyze the code structure.

Preparations

We recommend using VS2015 Update3 as your IDE: http://www.bkjia.com/softjc/446184.html

You need to install the. NET Core runtime environment and development tools, which are provided here VS version: http://www.bkjia.com/softs/472362.html

Create a project

Create a project in VS, select ASP. NET Core Web Application (. NET Core) as the project type, and enter the project name csf-enbaseauth.

Coding

Create some helper classes

Create a folder Auth under the project root directory, and add two files: RSAKeyHelper. cs and tokenautexception. cs.

In RSAKeyHelper. cs

using System.Security.Cryptography;namespace CSTokenBaseAuth.Auth{  public class RSAKeyHelper  {    public static RSAParameters GenerateKey()    {      using (var key = new RSACryptoServiceProvider(2048))      {        return key.ExportParameters(true);      }    }  }}

In tokenautexception. cs

using System;using Microsoft.IdentityModel.Tokens;namespace CSTokenBaseAuth.Auth{  public class TokenAuthOption  {    public static string Audience { get; } = "ExampleAudience";    public static string Issuer { get; } = "ExampleIssuer";    public static RsaSecurityKey Key { get; } = new RsaSecurityKey(RSAKeyHelper.GenerateKey());    public static SigningCredentials SigningCredentials { get; } = new SigningCredentials(Key, SecurityAlgorithms.RsaSha256Signature);    public static TimeSpan ExpiresSpan { get; } = TimeSpan.FromMinutes(20);  }}

Startup. cs

Add the following code to ConfigureServices:

services.AddAuthorization(auth =>{  auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()    .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme‌​)    .RequireAuthenticatedUser().Build());});

The complete code should be like this

public void ConfigureServices(IServiceCollection services){  // Add framework services.  services.AddApplicationInsightsTelemetry(Configuration);  // Enable the use of an [Authorize("Bearer")] attribute on methods and classes to protect.  services.AddAuthorization(auth =>  {    auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()      .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme‌​)      .RequireAuthenticatedUser().Build());  });  services.AddMvc();}

Add the following code to the Configure method:

app.UseExceptionHandler(appBuilder => {  appBuilder.Use(async (context, next) => {    var error = context.Features[typeof(IExceptionHandlerFeature)] as IExceptionHandlerFeature;    //when authorization has failed, should retrun a json message to client    if (error != null && error.Error is SecurityTokenExpiredException)    {      context.Response.StatusCode = 401;      context.Response.ContentType = "application/json";      await context.Response.WriteAsync(JsonConvert.SerializeObject(        new { authenticated = false, tokenExpired = true }      ));    }    //when orther error, retrun a error message json to client    else if (error != null && error.Error != null)    {      context.Response.StatusCode = 500;      context.Response.ContentType = "application/json";      await context.Response.WriteAsync(JsonConvert.SerializeObject(        new { success = false, error = error.Error.Message }      ));    }    //when no error, do next.    else await next();  });});

This code is mainly used for Handle Error. For example, an exception is thrown when authentication fails, and this exception is handled here.

Next, add the following code in the same method,

app.UseExceptionHandler(appBuilder => {  appBuilder.Use(async (context, next) => {    var error = context.Features[typeof(IExceptionHandlerFeature)] as IExceptionHandlerFeature;    //when authorization has failed, should retrun a json message to client    if (error != null && error.Error is SecurityTokenExpiredException)    {      context.Response.StatusCode = 401;      context.Response.ContentType = "application/json";      await context.Response.WriteAsync(JsonConvert.SerializeObject(        new { authenticated = false, tokenExpired = true }      ));    }    //when orther error, retrun a error message json to client    else if (error != null && error.Error != null)    {      context.Response.StatusCode = 500;      context.Response.ContentType = "application/json";      await context.Response.WriteAsync(JsonConvert.SerializeObject(        new { success = false, error = error.Error.Message }      ));    }    //when no error, do next.    else await next();  });});

Apply JwtBearerAuthentication

app.UseJwtBearerAuthentication(new JwtBearerOptions {  TokenValidationParameters = new TokenValidationParameters {    IssuerSigningKey = TokenAuthOption.Key,    ValidAudience = TokenAuthOption.Audience,    ValidIssuer = TokenAuthOption.Issuer,    ValidateIssuerSigningKey = true,    ValidateLifetime = true,    ClockSkew = TimeSpan.FromMinutes(0)  }});

The complete code should be like this

using System;using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Logging;using Microsoft.AspNetCore.Authorization;using Microsoft.AspNetCore.Authentication.JwtBearer;using CSTokenBaseAuth.Auth;using Microsoft.AspNetCore.Diagnostics;using Microsoft.IdentityModel.Tokens;using Microsoft.AspNetCore.Http;using Newtonsoft.Json;namespace CSTokenBaseAuth{  public class Startup  {    public Startup(IHostingEnvironment env)    {      var builder = new ConfigurationBuilder()        .SetBasePath(env.ContentRootPath)        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);      if (env.IsEnvironment("Development"))      {        // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.        builder.AddApplicationInsightsSettings(developerMode: true);      }      builder.AddEnvironmentVariables();      Configuration = builder.Build();    }    public IConfigurationRoot Configuration { get; }    // This method gets called by the runtime. Use this method to add services to the container    public void ConfigureServices(IServiceCollection services)    {      // Add framework services.      services.AddApplicationInsightsTelemetry(Configuration);      // Enable the use of an [Authorize("Bearer")] attribute on methods and classes to protect.      services.AddAuthorization(auth =>      {        auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()          .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme‌​)          .RequireAuthenticatedUser().Build());      });      services.AddMvc();    }    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)    {      loggerFactory.AddConsole(Configuration.GetSection("Logging"));      loggerFactory.AddDebug();      app.UseApplicationInsightsRequestTelemetry();      app.UseApplicationInsightsExceptionTelemetry();      #region Handle Exception      app.UseExceptionHandler(appBuilder => {        appBuilder.Use(async (context, next) => {          var error = context.Features[typeof(IExceptionHandlerFeature)] as IExceptionHandlerFeature;          //when authorization has failed, should retrun a json message to client          if (error != null && error.Error is SecurityTokenExpiredException)          {            context.Response.StatusCode = 401;            context.Response.ContentType = "application/json";            await context.Response.WriteAsync(JsonConvert.SerializeObject(              new { authenticated = false, tokenExpired = true }            ));          }          //when orther error, retrun a error message json to client          else if (error != null && error.Error != null)          {            context.Response.StatusCode = 500;            context.Response.ContentType = "application/json";            await context.Response.WriteAsync(JsonConvert.SerializeObject(              new { success = false, error = error.Error.Message }            ));          }          //when no error, do next.          else await next();        });      });      #endregion      #region UseJwtBearerAuthentication      app.UseJwtBearerAuthentication(new JwtBearerOptions {        TokenValidationParameters = new TokenValidationParameters {          IssuerSigningKey = TokenAuthOption.Key,          ValidAudience = TokenAuthOption.Audience,          ValidIssuer = TokenAuthOption.Issuer,          ValidateIssuerSigningKey = true,          ValidateLifetime = true,          ClockSkew = TimeSpan.FromMinutes(0)        }      });      #endregion      app.UseMvc(routes =>      {        routes.MapRoute(          name: "default",          template: "{controller=Login}/{action=Index}");      });    }  }}

Create a new Web API Controller Class in Controllers and name it TokenAuthController. cs. Here we will complete the logon authorization

Add two classes under the same file to simulate the user model and user storage respectively. The Code should be like this

public class User{  public Guid ID { get; set; }  public string Username { get; set; }  public string Password { get; set; }}public static class UserStorage{  public static List<User> Users { get; set; } = new List<User> {    new User {ID=Guid.NewGuid(),Username="user1",Password = "user1psd" },    new User {ID=Guid.NewGuid(),Username="user2",Password = "user2psd" },    new User {ID=Guid.NewGuid(),Username="user3",Password = "user3psd" }  };}

Add the following method to TokenAuthController. cs:

private string GenerateToken(User user, DateTime expires){  var handler = new JwtSecurityTokenHandler();    ClaimsIdentity identity = new ClaimsIdentity(    new GenericIdentity(user.Username, "TokenAuth"),    new[] {      new Claim("ID", user.ID.ToString())    }  );  var securityToken = handler.CreateToken(new SecurityTokenDescriptor  {    Issuer = TokenAuthOption.Issuer,    Audience = TokenAuthOption.Audience,    SigningCredentials = TokenAuthOption.SigningCredentials,    Subject = identity,    Expires = expires  });  return handler.WriteToken(securityToken);}

This method only generates an Auth Token. Next we will add another method to call it.

Add the following code to the same file:

[HttpPost]public string GetAuthToken(User user){  var existUser = UserStorage.Users.FirstOrDefault(u => u.Username == user.Username && u.Password == user.Password);  if (existUser != null)  {    var requestAt = DateTime.Now;    var expiresIn = requestAt + TokenAuthOption.ExpiresSpan;    var token = GenerateToken(existUser, expiresIn);    return JsonConvert.SerializeObject(new {      stateCode = 1,      requertAt = requestAt,      expiresIn = TokenAuthOption.ExpiresSpan.TotalSeconds,      accessToken = token    });  }  else  {    return JsonConvert.SerializeObject(new { stateCode = -1, errors = "Username or password is invalid" });  }}

The complete code of this file should be like this

using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using Microsoft.AspNetCore.Mvc;using Newtonsoft.Json;using System.IdentityModel.Tokens.Jwt;using System.Security.Claims;using System.Security.Principal;using Microsoft.IdentityModel.Tokens;using CSTokenBaseAuth.Auth;namespace CSTokenBaseAuth.Controllers{  [Route("api/[controller]")]  public class TokenAuthController : Controller  {    [HttpPost]    public string GetAuthToken(User user)    {      var existUser = UserStorage.Users.FirstOrDefault(u => u.Username == user.Username && u.Password == user.Password);      if (existUser != null)      {        var requestAt = DateTime.Now;        var expiresIn = requestAt + TokenAuthOption.ExpiresSpan;        var token = GenerateToken(existUser, expiresIn);        return JsonConvert.SerializeObject(new {          stateCode = 1,          requertAt = requestAt,          expiresIn = TokenAuthOption.ExpiresSpan.TotalSeconds,          accessToken = token        });      }      else      {        return JsonConvert.SerializeObject(new { stateCode = -1, errors = "Username or password is invalid" });      }    }    private string GenerateToken(User user, DateTime expires)    {      var handler = new JwtSecurityTokenHandler();            ClaimsIdentity identity = new ClaimsIdentity(        new GenericIdentity(user.Username, "TokenAuth"),        new[] {          new Claim("ID", user.ID.ToString())        }      );      var securityToken = handler.CreateToken(new SecurityTokenDescriptor      {        Issuer = TokenAuthOption.Issuer,        Audience = TokenAuthOption.Audience,        SigningCredentials = TokenAuthOption.SigningCredentials,        Subject = identity,        Expires = expires      });      return handler.WriteToken(securityToken);    }  }  public class User  {    public Guid ID { get; set; }    public string Username { get; set; }    public string Password { get; set; }  }  public static class UserStorage  {    public static List<User> Users { get; set; } = new List<User> {      new User {ID=Guid.NewGuid(),Username="user1",Password = "user1psd" },      new User {ID=Guid.NewGuid(),Username="user2",Password = "user2psd" },      new User {ID=Guid.NewGuid(),Username="user3",Password = "user3psd" }    };  }}

Next we will complete the authorization Verification Section

Create a new Web API Controller Class in Controllers and name it ValuesController. cs

Add the following code

public string Get(){  var claimsIdentity = User.Identity as ClaimsIdentity;  var id = claimsIdentity.Claims.FirstOrDefault(c => c.Type == "ID").Value;  return $"Hello! {HttpContext.User.Identity.Name}, your ID is:{id}";}

Add decoration attributes for methods

[HttpGet] [Authorize ("Bearer")] the complete file code should be using System. linq; using Microsoft. aspNetCore. mvc; using Microsoft. aspNetCore. authorization; using System. security. claims; namespace CSTokenBaseAuth. controllers {[Route ("api/[controller]")] public class ValuesController: Controller {[HttpGet] [Authorize ("Bearer")] public string Get () {var claimsIdentity = User. identity as ClaimsIdentity; var id = claimsIdent Ity. Claims. FirstOrDefault (c => c. Type = "ID"). Value; return $ "Hello! {HttpContext. User. Identity. Name}, your ID is: {id }";}}}

Finally, let's add a view.

Create a new Web Controller Class in Controllers and name it LoginController. cs

The code here should be like this

using Microsoft.AspNetCore.Mvc;namespace CSTokenBaseAuth.Controllers{  [Route("[controller]/[action]")]  public class LoginController : Controller  {    public IActionResult Index()    {      return View();    }  }}

Create a directory named Login under the project Views directory and create an Index. cshtml file.

The code looks like this.

The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.