或者应该包含什么信息呢?

    1.这个人是谁?

    2.这个人可以用此token访问什么样的内容?(scope)

    3.token的过期时间 (expire)

    4.谁发行的token。

    5.其他任何你希望加入的声明(Claims)

 那我们为什么要使用token呢?使用session或者用redis来实现stateServer不好吗?

    1.token是低(无)状态的,Statelessness

    2.token可以与移动端应用紧密结合

    3.支持多平台服务器和分布式微服务

拿到token后如何带入HTTP请求传给后台?

 答案是两种方式,Cookies和Authorization Header。那么什么时候放到Cookies中,什么时候又放到Authentication中呢?

第一,如果是在Web应用,则放到Cookies当中,并且应该是HttpOnly的,js不能直接对其进行操作,安全性会比将其存在Web Stroage中好一些,因为在Web Storage当中的内容,可以很容的被潜在的XSS脚本攻击并获取。在HttpOnly的cookies当中会相对安全一些,不过也有潜在的CSRF跨站伪造请求的危险,不过这种hack的手段成功率是很低的,有兴趣的朋友可以自行看一下CSRF原理。

第二,如果是手机移动端应用的话,那一定是存储在App本地,并由Authorization Header带到后台并得到身份认证。

WebApp Cookies Authentication

上一段前两周写的最原始的小Demo吧,没有数据库访问等,可根据demo自行改变 ,现在的新代码已经加入了很多业务在其中

startup.cs代码

using Microsoft.AspNetCore.Authentication.Cookies;

using Microsoft.AspNetCore.Builder;

using Microsoft.AspNetCore.Hosting;

using Microsoft.AspNetCore.Http;

using Microsoft.AspNetCore.Http.Authentication;

using Microsoft.Extensions.Configuration;

using Microsoft.Extensions.DependencyInjection;

using Microsoft.Extensions.Logging;

using System.Collections.Generic;

using System.Security.Claims;

using Wings.AuthenticationApp.Middleware;

namespace Wings.AuthenticationApp

{

public class Startup

{

public Startup(IHostingEnvironment env)

{

var builder = new ConfigurationBuilder()

.SetBasePath(env.ContentRootPath)

.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)

.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)

.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.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.UseCookieAuthentication(CookieAuthMiddleware.GetOptions());

app.UseOwin();

app.UseCors(a => { a.AllowAnyOrigin(); });

app.UseMvc();

// Listen for login and logout requests

app.Map("/login", builder =>

{

builder.Run(async context =>

{

var name = context.Request.Form["name"];

var pwd = context.Request.Form["pwd"];

if (name == "wushuang" && pwd == "wushuang")

{

var claims = new List<Claim>() { new Claim("name", name), new Claim("role", "admin") };

var identity = new ClaimsIdentity(claims, "password");

var principal = new ClaimsPrincipal(identity);

await context.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);

context.Response.Redirect("http://www.baidu.com");

}

else

{

await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

context.Response.Redirect("http://www.google.com");

}

});

});

//app.Map("/logout", builder =>

//{

//    builder.Run(async context =>

//    {

//        // Sign the user out / clear the auth cookie

//        await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

//        // Perform a simple redirect after logout

//        context.Response.Redirect("/");

//    });

//});

}

}

}

下面是Middleware---->CookieAuthMiddleware.cs的代码,

using Microsoft.AspNetCore.Authentication.Cookies;

using Microsoft.AspNetCore.Builder;

using Microsoft.AspNetCore.Http;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Security.Claims;

using System.Security.Principal;

using System.Threading.Tasks;

namespace Wings.AuthenticationApp.Middleware

{

public class CookieAuthMiddleware

{

public static CookieAuthenticationOptions GetOptions()

{

return new CookieAuthenticationOptions

{

AutomaticAuthenticate = true,

AutomaticChallenge = true,

LoginPath = new PathString("/login"),

LogoutPath = new PathString("/logout"),

AccessDeniedPath = new PathString("/test"),

CookieHttpOnly = false,  //默认就是True了

CookieName = "wings_access_token",

SlidingExpiration = true,

CookieManager = new ChunkingCookieManager()

};

}

}

public static class IdentityExtension

{

public static string FullName(this IIdentity identity)

{

var claim = ((ClaimsIdentity)identity).FindFirst("name");

return (claim != null) ? claim.Value : string.Empty;

}

public static string Role(this IIdentity identity)

{

var claim = ((ClaimsIdentity)identity).FindFirst("role");

return (claim != null) ? claim.Value : string.Empty;

}

}

}

对应如上demo,简单测试一下,结果如下:

首先使用错误的密码,来请求token endpoint,接下来我们看一下即使窗口,当有请求进入的时候,我用如下代码判断用户的认证情况,拿到的结果必然是false:

接下来,我使用正确的账号密码,来打入token,判断结果一定为true,所以我使用自定义的拓展方法,来获取下,该用户token的信息:

如上demo没有加入一些容错机制,请注意。在用户认证成功后,可以进入带有Authorize Attribute的Action,否则401.如下是几个重要参数的解释

自定义Authentication Middle生产Token

Startup.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Threading.Tasks;

using Microsoft.AspNetCore.Builder;

using Microsoft.AspNetCore.Hosting;

using Microsoft.Extensions.Configuration;

using Microsoft.Extensions.DependencyInjection;

using Microsoft.Extensions.Logging;

using Wings.TokenAuth.Middleware;

using System.Security.Claims;

using Microsoft.IdentityModel.Tokens;

using System.Text;

using Microsoft.Extensions.Options;

namespace Wings.TokenAuth

{

public class Startup

{

public Startup(IHostingEnvironment env)

{

var builder = new ConfigurationBuilder()

.SetBasePath(env.ContentRootPath)

.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)

.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)

.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.AddMvc();

}

// The secret key every token will be signed with.

// In production, you should store this securely in environment variables

// or a key management tool. Don't hardcode this into your application!

private static readonly string secretKey = "mysupersecret_secretkey!123";

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)

{

loggerFactory.AddConsole(LogLevel.Debug);

loggerFactory.AddDebug();

app.UseStaticFiles();

// Add JWT generation endpoint:

var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));

var options = new TokenProviderOptions

{

Audience = "ExampleAudience",

Issuer = "ExampleIssuer",

SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256),

};

app.UseMiddleware<TokenProviderMiddleware>(Options.Create(options));

app.UseMvc();

}

}

}

TokenProviderOptions.cs

using Microsoft.AspNetCore.Http;

using Microsoft.Extensions.Options;

using Microsoft.IdentityModel.Tokens;

using Newtonsoft.Json;

using System;

using System.Collections.Generic;

using System.IdentityModel.Tokens.Jwt;

using System.Linq;

using System.Security.Claims;

using System.Threading.Tasks;

namespace Wings.TokenAuth.Middleware

{

public class TokenProviderOptions

{

public string Path { get; set; } = "/token";

public string Issuer { get; set; }

public string Audience { get; set; }

public TimeSpan Expiration { get; set; } = TimeSpan.FromMinutes(5);

public SigningCredentials SigningCredentials { get; set; }

}

public class TokenProviderMiddleware

{

private readonly RequestDelegate _next;

private readonly TokenProviderOptions _options;

public TokenProviderMiddleware(

RequestDelegate next,

IOptions<TokenProviderOptions> options)

{

_next = next;

_options = options.Value;

}

public Task Invoke(HttpContext context)

{

// If the request path doesn't match, skip

if (!context.Request.Path.Equals(_options.Path, StringComparison.Ordinal))

{

             //use new JwtSecurityTokenHandler().ValidateToken() to valid token

return _next(context);

}

// Request must be POST with Content-Type: application/x-www-form-urlencoded

if (!context.Request.Method.Equals("POST")

|| !context.Request.HasFormContentType)

{

context.Response.StatusCode = 400;

return context.Response.WriteAsync("Bad request.");

}

return GenerateToken(context);

}

private async Task GenerateToken(HttpContext context)

{

var username = context.Request.Form["username"];

var password = context.Request.Form["password"];

var identity = await GetIdentity(username, password);

if (identity == null)

{

context.Response.StatusCode = 400;

await context.Response.WriteAsync("Invalid username or password.");

return;

}

var now = DateTime.UtcNow;

// Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims.

// You can add other claims here, if you want:

var claims = new Claim[]

{

new Claim(JwtRegisteredClaimNames.Sub, username),

new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),

new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(now).ToString(), ClaimValueTypes.Integer64)

};

// Create the JWT and write it to a string

var jwt = new JwtSecurityToken(

issuer: _options.Issuer,

audience: _options.Audience,

claims: claims,

notBefore: now,

expires: now.Add(_options.Expiration),

signingCredentials: _options.SigningCredentials);

var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

var response = new

{

access_token = encodedJwt,

expires_in = (int)_options.Expiration.TotalSeconds

};

// Serialize and return the response

context.Response.ContentType = "application/json";

await context.Response.WriteAsync(JsonConvert.SerializeObject(response, new JsonSerializerSettings { Formatting = Formatting.Indented }));

}

private Task<ClaimsIdentity> GetIdentity(string username, string password)

{

// DON'T do this in production, obviously!

if (username == "wushuang" && password == "wushuang")

{

return Task.FromResult(new ClaimsIdentity(new System.Security.Principal.GenericIdentity(username, "Token"), new Claim[] { }));

}

// Credentials are invalid, or account doesn't exist

return Task.FromResult<ClaimsIdentity>(null);

}

public static long ToUnixEpochDate(DateTime date)

=> (long)Math.Round((date.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalSeconds);

}

}

下面上测试结果:

使用错误的账户和密码请求token

使用正确的账户和密码来请求,返回结果如下:

如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下加【推荐】按钮。
如果,您希望更容易地发现我的新博客,不妨点击下方红色【关注】的。
因为,我的分享热情也离不开您的肯定支持。

感谢您的阅读,我将持续输出分享,我是蜗牛, 保持学习,谨记谦虚。不端不装,有趣有梦。

参考文章和论文,不仅限于如下几篇,感谢国外大佬们有深度的分享:

http://stackoverflow.com/questions/29055477/oauth-authorization-service-in-asp-net-core

https://stormpath.com/blog/token-authentication-asp-net-core

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware#fundamentals-middleware

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/cookie#controlling-cookie-options

https://stormpath.com/blog/token-authentication-asp-net-core

相关文章:

  • AspNet Identity 和 Owin 谁是谁

  • ASP.NET Core 之 Identity 入门(一)

  • ASP.NET Core 之 Identity 入门(二)

  • ASP.NET Core 之 Identity 入门(三)

原文链接:http://www.cnblogs.com/tdws/p/6536864.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

Asp.Net Core Authentication Middleware And Generate Token相关推荐

  1. ASP.NET Core 实战:基于 Jwt Token 的权限控制全揭露

    一.前言 在涉及到后端项目的开发中,如何实现对于用户权限的管控是需要我们首先考虑的,在实际开发过程中,我们可能会运用一些已经成熟的解决方案帮助我们实现这一功能,而在 Grapefruit.VuCore ...

  2. 利用Asp.Net Core的MiddleWare思想处理复杂业务流程

    最近利用Asp.Net Core 的MiddleWare思想对公司的古老代码进行重构,在这里把我的设计思路分享出来,希望对大家处理复杂的流程业务能有所帮助. 背景 一个流程初始化接口,接口中根据传入的 ...

  3. ASP.NET Core中间件(Middleware)实现WCF SOAP服务端解析

    ASP.NET Core中间件(Middleware)进阶学习实现SOAP 解析. 本篇将介绍实现ASP.NET Core SOAP服务端解析,而不是ASP.NET Core整个WCF host. 因 ...

  4. 在ASP.NET Core使用Middleware模拟Custom Error Page功能

    一.使用场景 在传统的ASP.NET MVC中,我们可以使用HandleErrorAttribute特性来具体指定如何处理Action抛出的异常.只要某个Action设置了HandleErrorAtt ...

  5. ASP.NET Core Authentication and Authorization

    最近把一个Asp .net core 2.0的项目迁移到Asp .net core 3.1,项目启动的时候直接报错: InvalidOperationException: Endpoint CoreA ...

  6. ASP.NET Core -中间件(Middleware)使用

    ASP.NET Core开发,开发并使用中间件(Middleware). 中间件是被组装成一个应用程序管道来处理请求和响应的软件组件. 每个组件选择是否传递给管道中的下一个组件的请求,并能之前和下一组 ...

  7. ASP.NET Core使用Middleware有条件地允许访问路由

    问题 有时,我们可能在Web API中包含一些具有调试功能的请求.比如我们上次的文章中"晕了!这个配置值从哪来的?"使用的获取配置值的功能: endpoints.MapGet(&q ...

  8. 一张大图了解ASP.NET Core 3.1 中的Authentication与Authorization

    下面是一张ASP.NET Core 3.1 中关于Authentication与Authorization的主流程框线图,点击这里查看全图:https://johnnyqian.net/images/ ...

  9. 为什么应该在业务层实现管道模式,而不用ASP.NET Core Middleware实现 | 2点原因和实现方式...

    前言 ASP.NET Core的Middleware(中间件)就是使用了管道模式: Request(请求)在管道中传递,依次经过管道中的每一个MiddleWare进行处理. MiddleWare就像一 ...

最新文章

  1. 【软件工程】RUP与软件开发5大模型
  2. 基于Opencv实现眼睛控制鼠标
  3. 详解JavaScript中的this
  4. hdu 1788 Chinese remainder theorem again 【crt的具体过程】
  5. 如何让你的webapp也能跳窗口搜索
  6. python优雅编程_Python优雅地可视化数据
  7. python实现将文件夹下文件随机移动指定数量到另一个文件夹下
  8. ECharts实例开发学习笔记二——时间轴
  9. LibreOJ 6283 数列分块入门 7(区间加区间乘区间求和)
  10. 原来做浏览器这么简单
  11. 学习笔记:模式学习-生成器模式
  12. 想和华为人一样移动办公?送你一份华为云WeLink入门“说明书”!
  13. js 打印去掉页眉页脚页码_js页面打印去除页眉页脚
  14. 计算机视觉教程2-6:八大图像特效算法制作你的专属滤镜(附Python代码)
  15. 初中数学抽象教学的案例_初中数学教学案例与反思
  16. wireshark 找不到wifi无线网卡的解决方法
  17. 软件测试工程师面试如何描述自动化测试是怎么实现的?
  18. UE4使用蓝图实现自动双开关门
  19. python视频在线教程_600集Python从小白到大神
  20. Mysql的基本操作和用户权限----2021(ZSD版)

热门文章

  1. 关于YoYo.Cms
  2. SharePoint 2007 Select People and Groups中搜索不到其他Domain账户的问题[已解决]
  3. ISAPI_Rewrite伪静态配置
  4. 登陆xp系统,无法显示桌面
  5. GitHub Copilot 现已登陆 Visual Studio!
  6. 程序怎么跑着 就卡死,句柄泄漏,内存泄漏了
  7. C# WPF文本框TextEdit不以科学计数法显示
  8. .NET 6 平台系列1 .NET Framework发展历程
  9. WPF 仿QQ登录框翻转效果
  10. .NET 5 部署在docker上运行