本文介绍的是Winform宿主Asp.net WebAPI的过程,利用了Microsoft.AspNet.WebApi.OwinSelfHost.

Asp.NET WebAPI中的授权验证有很多:

例如选用Bearer Token验证:利用Asp.Net Owin实现:基本套路为:(宿主Winform程序为例)

1:nuget owin相关的安装包:

Microsoft.AspNet.WebApi.OwinSelfHost

Microsoft.Owin.Security.OAuth

Microsoft.AspNet.WebApi.Owin

其他相关依赖包自动下载;

2:开启webapi服务:

 Microsoft.Owin.Hosting.WebApp.Start<Startup>("http://127.0.0.1:8996/");

Startup类如下:

public class Startup
{public void Configuration(IAppBuilder app){SimpleAuthorizationProvider provider = new SimpleAuthorizationProvider();OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions(){AllowInsecureHttp = true,TokenEndpointPath = new PathString("/api/auth/signin"),AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),Provider = provider,};app.UseOAuthAuthorizationServer(OAuthServerOptions);app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions);            HttpConfiguration config = new HttpConfiguration();config.MapHttpAttributeRoutes();config.Routes.MapHttpRoute(name: "DefaultApi",routeTemplate: "api/{controller}/{action}");app.UseWebApi(config);}
}

SimpleAuthorizationProvider .cs

/// <summary>/// Token验证/// </summary>public class SimpleAuthorizationProvider : OAuthAuthorizationServerProvider{public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context){          await Task.Factory.StartNew(() => context.Validated());}public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context){await Task.Factory.StartNew(() => context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }));            string userName = context.UserName;string pwd = context.Password;if (userName == "test" && pwd == "1"){var identity = new ClaimsIdentity(context.Options.AuthenticationType);     identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));context.Validated(identity);}else{context.SetError("invalid_grant", "用户和密码验证失败!");}}}

3:Postman验证:

其中:grant_type 和 username、password为固定的参数,且grant_type固定为"password",否则请求token不成功;

至于为何是这样,参考Owin框架源码分析就可以知道原因:

源码地址:https://github.com/aspnet/AspNetKatana

源码位置:TokenEndpointRequest.cs 构造函数处

重点来了,如果希望改变获取Token的参数,该如何处理呢?

解决办法如下:

步骤1:找到源码下如下图所示两个文件:原样复制过来:

步骤2:把如上两个文件粘贴到项目中,重命名:如:MyOAuthAuthorizationServerHandler和

MyOAuthAuthorizationServerMiddleware

步骤3:修改Setup 中的Configuration方法:

public void Configuration(IAppBuilder app){SimpleAuthorizationProvider provider = new SimpleAuthorizationProvider();OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions(){AllowInsecureHttp = true,TokenEndpointPath = new PathString("/api/auth/signin"),AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),Provider = provider,};//app.UseOAuthAuthorizationServer(OAuthServerOptions);//app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions() { });app.Use(typeof(MyOAuthAuthorizationServerMiddleware), app, OAuthServerOptions);app.UseOAuthBearerTokens(OAuthServerOptions);HttpConfiguration config = new HttpConfiguration();config.MapHttpAttributeRoutes();config.Routes.MapHttpRoute(name: "DefaultApi",routeTemplate: "api/{controller}/{action}");app.UseWebApi(config);}

步骤4:修改 MyOAuthAuthorizationServerMiddleware 下获取HttpRequest中 Body参数的代码:

如下所示:

  private async Task InvokeTokenEndpointAsync(){DateTimeOffset currentUtc = Options.SystemClock.UtcNow;// remove milliseconds in case they don't round-tripcurrentUtc = currentUtc.Subtract(TimeSpan.FromMilliseconds(currentUtc.Millisecond));IDictionary<string, string[]> formDic = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase);formDic.Add(Constants.Parameters.GrantType, new string[] { "password" });using (var reader = new StreamReader(Request.Body, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 4 * 1024, leaveOpen: true)){string text = await reader.ReadToEndAsync();var userInfo=  JsonConvert.DeserializeObject<UserInfo>(text);formDic.Add(Constants.Parameters.Username, new string[] { userInfo.User });formDic.Add(Constants.Parameters.Password, new string[] { userInfo.Pwd });}IFormCollection form=new FormCollection(formDic);//以下是原来的代码//IFormCollection form = await Request.ReadFormAsync();var clientContext = new OAuthValidateClientAuthenticationContext(Context, Options, form);await Options.Provider.ValidateClientAuthentication(clientContext);//....省略后面的代码
}

关键思路就是读取Body Stream流,然后解析得到Json字符串,转成对象后,给IFormCollection赋值实例化。此后继续Owin框架的功能流程不变;

实现效果如下图所示:

如果要自定义返回的Json格式呢,例如变成下面这样:

同理:在最后的返回结果处,修改成想要的格式:

 private async Task InvokeTokenEndpointAsync(){DateTimeOffset currentUtc = Options.SystemClock.UtcNow;// remove milliseconds in case they don't round-tripcurrentUtc = currentUtc.Subtract(TimeSpan.FromMilliseconds(currentUtc.Millisecond));IDictionary<string, string[]> formDic = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase);formDic.Add(Constants.Parameters.GrantType, new string[] { "password" });using (var reader = new StreamReader(Request.Body, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 4 * 1024, leaveOpen: true)){string text = await reader.ReadToEndAsync();var userInfo=  JsonConvert.DeserializeObject<UserInfo>(text);formDic.Add(Constants.Parameters.Username, new string[] { userInfo.User });formDic.Add(Constants.Parameters.Password, new string[] { userInfo.Pwd });}IFormCollection form=new FormCollection(formDic);//以下是原来的代码//IFormCollection form = await Request.ReadFormAsync();var clientContext = new OAuthValidateClientAuthenticationContext(Context, Options, form);await Options.Provider.ValidateClientAuthentication(clientContext);if (!clientContext.IsValidated){_logger.WriteError("clientID is not valid.");if (!clientContext.HasError){clientContext.SetError(Constants.Errors.InvalidClient);}await SendErrorAsJsonAsync(clientContext);return;}var tokenEndpointRequest = new TokenEndpointRequest(form);var validatingContext = new OAuthValidateTokenRequestContext(Context, Options, tokenEndpointRequest, clientContext);AuthenticationTicket ticket = null;if (tokenEndpointRequest.IsAuthorizationCodeGrantType){// Authorization Code Grant http://tools.ietf.org/html/rfc6749#section-4.1// Access Token Request http://tools.ietf.org/html/rfc6749#section-4.1.3ticket = await InvokeTokenEndpointAuthorizationCodeGrantAsync(validatingContext, currentUtc);}else if (tokenEndpointRequest.IsResourceOwnerPasswordCredentialsGrantType){// Resource Owner Password Credentials Grant http://tools.ietf.org/html/rfc6749#section-4.3// Access Token Request http://tools.ietf.org/html/rfc6749#section-4.3.2ticket = await InvokeTokenEndpointResourceOwnerPasswordCredentialsGrantAsync(validatingContext, currentUtc);}else if (tokenEndpointRequest.IsClientCredentialsGrantType){// Client Credentials Grant http://tools.ietf.org/html/rfc6749#section-4.4// Access Token Request http://tools.ietf.org/html/rfc6749#section-4.4.2ticket = await InvokeTokenEndpointClientCredentialsGrantAsync(validatingContext, currentUtc);}else if (tokenEndpointRequest.IsRefreshTokenGrantType){// Refreshing an Access Token// http://tools.ietf.org/html/rfc6749#section-6ticket = await InvokeTokenEndpointRefreshTokenGrantAsync(validatingContext, currentUtc);}else if (tokenEndpointRequest.IsCustomExtensionGrantType){// Defining New Authorization Grant Types// http://tools.ietf.org/html/rfc6749#section-8.3ticket = await InvokeTokenEndpointCustomGrantAsync(validatingContext, currentUtc);}else{// Error Response http://tools.ietf.org/html/rfc6749#section-5.2// The authorization grant type is not supported by the// authorization server._logger.WriteError("grant type is not recognized");validatingContext.SetError(Constants.Errors.UnsupportedGrantType);}if (ticket == null){await SendErrorAsJsonAsync(validatingContext);return;}ticket.Properties.IssuedUtc = currentUtc;ticket.Properties.ExpiresUtc = currentUtc.Add(Options.AccessTokenExpireTimeSpan);var tokenEndpointContext = new OAuthTokenEndpointContext(Context, Options, ticket, tokenEndpointRequest);await Options.Provider.TokenEndpoint(tokenEndpointContext);if (tokenEndpointContext.TokenIssued){ticket = new AuthenticationTicket(tokenEndpointContext.Identity, tokenEndpointContext.Properties);}else{_logger.WriteError("Token was not issued to tokenEndpointContext");validatingContext.SetError("invalid_grant");await SendErrorAsJsonAsync(validatingContext);return;}var accessTokenContext = new AuthenticationTokenCreateContext(Context, Options.AccessTokenFormat, ticket);await Options.AccessTokenProvider.CreateAsync(accessTokenContext);string accessToken = accessTokenContext.Token;if (string.IsNullOrEmpty(accessToken)){accessToken = accessTokenContext.SerializeTicket();}DateTimeOffset? accessTokenExpiresUtc = ticket.Properties.ExpiresUtc;var refreshTokenCreateContext = new AuthenticationTokenCreateContext(Context, Options.RefreshTokenFormat, accessTokenContext.Ticket);await Options.RefreshTokenProvider.CreateAsync(refreshTokenCreateContext);string refreshToken = refreshTokenCreateContext.Token;var tokenEndpointResponseContext = new OAuthTokenEndpointResponseContext(Context, Options, ticket, tokenEndpointRequest, accessToken, tokenEndpointContext.AdditionalResponseParameters);await Options.Provider.TokenEndpointResponse(tokenEndpointResponseContext);var memory = new MemoryStream();byte[] body;/***public T Data { get; set; }public bool IsError { get; set; }public string Message { get; set; }public int ErrorCode { get; set; }*/var timeConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" };using (var writer = new JsonTextWriter(new StreamWriter(memory))){writer.WriteStartObject();writer.WritePropertyName("Data");TokenInfo tokenInfo = new TokenInfo();tokenInfo.Token = accessToken;tokenInfo.TokenType = "bearer";JsonSerializer serializer = new JsonSerializer();//var jsn = new JObject();//jsn["Data"] = JObject.FromObject( tokenInfo);serializer.Serialize(writer, tokenInfo);            writer.WritePropertyName("IsError");writer.WriteValue(false);writer.WritePropertyName("Message");writer.WriteValue(String.Empty);writer.WritePropertyName("ErrorCode");writer.WriteValue(0);if (accessTokenExpiresUtc.HasValue){TimeSpan? expiresTimeSpan = accessTokenExpiresUtc - currentUtc;var expiresIn = (long)expiresTimeSpan.Value.TotalSeconds;if (expiresIn > 0){writer.WritePropertyName("expires_in");writer.WriteValue(expiresIn);}}if (!String.IsNullOrEmpty(refreshToken)){writer.WritePropertyName("refresh_token");writer.WriteValue(refreshToken);}foreach (var additionalResponseParameter in tokenEndpointResponseContext.AdditionalResponseParameters){writer.WritePropertyName(additionalResponseParameter.Key);writer.WriteValue(additionalResponseParameter.Value);}writer.WriteEndObject();writer.Flush();body = memory.ToArray();}Response.ContentType = "application/json;charset=UTF-8";Response.Headers.Set("Cache-Control", "no-cache");Response.Headers.Set("Pragma", "no-cache");Response.Headers.Set("Expires", "-1");Response.ContentLength = body.Length;await Response.WriteAsync(body, Request.CallCancelled);}

参考#region 自定义格式部分代码

Winform宿主Asp.Net WebApi中Owin 自定义Token请求参数相关推荐

  1. ASP.NET Core中显示自定义错误页面-增强版

    之前的博文 ASP.NET Core中显示自定义错误页面 中的方法是在项目中硬编码实现的,当有多个项目时,就会造成不同项目之间的重复代码,不可取. 在这篇博文中改用middleware实现,并且放在独 ...

  2. 如何在ASP.NET Core中编写自定义日志记录提供程序

    目录 介绍 如何实现所需的接口 基础类和附件 FileLoggerProvider具体类及其附件 1. ConfigureLogging() 2. appsettings.json文件 介绍 源代码可 ...

  3. 如何在ASP.NET Core中创建自定义AuthorizeAttribute?

    本文翻译自:How do you create a custom AuthorizeAttribute in ASP.NET Core? I'm trying to make a custom aut ...

  4. ASP.NET WebApi 基于JWT实现Token签名认证

    一.前言 开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NET WebService服务中可以通过SoapHead验证机制 ...

  5. php中post提交参数_PHP中Http协议post请求参数

    这篇文章主要介绍了Http协议post请求参数的相关资料,需要的朋友可以参考下 本文给大家介绍PHP中Http协议post请求参数,具体内容如下所示: WEB开发中信息基本全是在POST与GET请求与 ...

  6. 在ASP.NET Core中创建自定义端点可视化图

    在上篇文章中,我为构建自定义端点可视化图奠定了基础,正如我在第一篇文章中展示的那样.该图显示了端点路由的不同部分:文字值,参数,动词约束和产生结果的端点: 在本文中,我将展示如何通过创建一个自定义的D ...

  7. ASP.NET WebAPI 中的参数绑定

    当 WebAPI 调用 Controller 上的方法时, 必须为其参数赋值, 这个过程就是参数绑定. 本文介绍 WebAPI 如何绑定参数, 以及如何进行自定义. WebAPI 默认使用下面的规则进 ...

  8. ASP.NET Core中如何调整HTTP请求大小的几种方式

    一.前言 一般的情况下,我们都无需调用HTTP请求的大小,只有在上传一些大文件,或者使用HTTP协议写入较大的值时(如调用WebService)才可能会调用HTTP最大请求值. 在ASP.NET Co ...

  9. Jmeter并发压测-自定义不同请求参数

    目录 背景 下载Jmeter 1. 更改语言 2. 创建线程组 3. 添加变量 3. 创建Http接口 4. 创建察看结果树 5. 执行结果 背景 虽然可以请求相同的接口做测试,但是请求参数每次都是相 ...

最新文章

  1. AI四巨头Google、DeepMind、Microsoft、Uber深度学习框架大比拼
  2. 混合使用Azure LB和ILB访问相同web服务(2)
  3. Spring MVC-10循序渐进之文件下载
  4. linux eth0 device not found,nVidia集成驱动已经安装了,但是Device not found,我的网卡怎么用呢?...
  5. 我用 Python 帮朋友做了张图,结果
  6. 栈和队列之LinekedList(双端队列)
  7. 算法题解:动态规划解0-1背包问题
  8. 20145226夏艺华 后门原理与实践
  9. python基于udp的网络聊天室再用tkinter显示_Python实现网络聊天室的示例代码(支持多人聊天与私聊)...
  10. [Perforce]password (P4PASSWD) invalid or unset. 的错误解决
  11. python importlib qpython_Python imports指南:Python的导入有更好的理解
  12. web3sdk 怎么配置连接区块链节点
  13. mysql5.7.22.zip使用,mysql5.7.22 zip 版安装
  14. Dll注入技术之驱动注入
  15. IPA安装的几种方法
  16. 安卓关于inflate方法的总结
  17. 鸡啄米C++和MFC学习网址链接
  18. SpringBoot(45) 实现快递物流查询(阿里云)
  19. php面向对象手册,php学习笔记之面向对象
  20. Dynamics 365 设置Postman environment For WebAPI

热门文章

  1. 极速office(Word)怎么插入艺术字
  2. 数字图像处理-知识体系概括
  3. mac修改chrome的刷新及开发者工具等快捷键
  4. 用bat几行代码让你轻松用上office2019
  5. 解决kali访问HackTheBox网络不稳定
  6. 超详细的 Galgame 各种模拟器及工具使用教程
  7. 卸载ubuntu20.04自带软件
  8. A*算法实现猎人渡河问题
  9. 百度智能云 x 河北港口集团丨云上港口 智慧升级
  10. (附源码)计算机毕业设计SSM基于web在线学习系统