目录

1       大概思路... 1

2       Nginx集群之SSL证书的WebApi令牌验证... 1

3       Openssl生成SSL证书... 2

4       编写.NET WebApi的OnAuthorization身份验证... 2

5       编写.NET WebApi的ActionFilterAttribute令牌验证... 4

6       编写.NET WebApi的服务端... 6

7       编写.NET WebApi的客户端... 7

8       部署WebApi到局域网内3台PC机... 13

9       Nginx集群配置搭建... 13

10     运行结果... 15

11     总结... 16

1       大概思路

l  Nginx集群之SSL证书的WebApi令牌验证

l  Openssl生成SSL证书

l  编写.NET WebApi的OnAuthorization身份验证

l  编写.NET WebApi的ActionFilterAttribute令牌验证

l  编写.NET WebApi的服务端

l  编写.NET WebApi的客户端

l  部署WebApi到局域网内3台PC机

l  Nginx集群配置搭建

l  运行结果

l  总结

2       Nginx集群之SSL证书的WebApi令牌验证

Nginx在WebApi集群,除了OAUTH身份验证外,针对移动端的手机、平板电脑等,还经常使用Token令牌验证,通过服务器授权发出有效期的Token,客户端通过此Token在当前有效期内,进行访问获取信息数据。

Token验证在很多方面都广泛应用,举一个实际应用场景:A客户想通过接收邮件或者短信网址打开一个URL的PDF报表,但是又不想安装APP、或者访问我们的系统,连登录都不想登录。这时候,便可以使用一个有效期的Token,然后结合URL发送给用户,过了有效期,当前URL就失效。便可以解决用户临时访问的问题。

以下是本文讲述的主要结构图:

客户端输入用户名密码服务器,通过了用户名密码验证,其中一台WebApi服务器生成一个Token并返回https的响应。客户端收到Token保存在本地,带上token发出ajax请求、WebRequest请求,经过Action过滤器的检验,访问Action并返回数据。

Token令牌身份验证机制:

Nginx集群之SSL证书的WebApi令牌验证,如下图所示:

3       Openssl生成SSL证书

请参照《Nginx集群之SSL证书的WebApi微服务》

http://www.cnblogs.com/yongfeng/p/7921905.html

4       编写.NET WebApi的OnAuthorization身份验证

CustomAuthorizeAttribute.cs

using System.Web.Http;
using System.Web.Http.Controllers; namespace SSLWebApi.Controllers
{
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
//判断用户是否登录
if (actionContext.Request.Headers.Authorization != null)
{
string userInfo = System.Text.Encoding.Default.GetString(System.Convert.FromBase64String(actionContext.Request.Headers.Authorization.Parameter));
//用户验证逻辑
if (string.Equals(userInfo, string.Format("{0}:{1}", "zhyongfeng", "")))
{
IsAuthorized(actionContext);
}
else
{
HandleUnauthorizedRequest(actionContext);
}
}
else
{
HandleUnauthorizedRequest(actionContext);
}
}
protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
{
var challengeMessage = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
challengeMessage.Headers.Add("WWW-Authenticate", "Basic");
throw new System.Web.Http.HttpResponseException(challengeMessage);
}
}
}

生成Token

BaseController.cs

using SSLWebApi.Models;
using System;
using System.Web;
using System.Web.Http; namespace SSLWebApi.Controllers
{
/// <summary>
/// BaseController继承BaseController则需要身份验证
/// </summary>
[CustomAuthorize]
[RoutePrefix("api/Base")]
public class BaseController : ApiController
{
[HttpGet]
[Route("Login")]
public string Login(string userId)
{
if (HttpRuntime.Cache.Get(userId) == null)
{
return CreateToken(userId);
}
else
{
HttpRuntime.Cache.Remove(userId);
return CreateToken(userId);
}
} /// <summary>
/// 生成token
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
private string CreateToken(string userId)
{
Token token = new Token();
token.UserId = userId;
token.SignToken = Guid.NewGuid();
token.Seconds = ;
token.ExpireTime = DateTime.Now.AddSeconds(token.Seconds);
HttpRuntime.Cache.Insert(token.UserId, token, null, token.ExpireTime, TimeSpan.Zero);
return token.SignToken.ToString();
}
}
}

5       编写.NET WebApi的ActionFilterAttribute令牌验证

WebApiSecurityFilter.cs

using SSLWebApi.Models;
using System;
using System.Linq;
using System.Net.Http;
using System.Web;
using System.Web.Http.Controllers;
using System.Web.Http.Filters; namespace SSLWebApi.Filter
{
public class WebApiSecurityFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{ if (actionContext.ActionDescriptor.ActionName == "Login")
{
//登录成功则生成token
base.OnActionExecuting(actionContext);
return;
}
else
{
//判断token令牌
HttpRequestMessage request = actionContext.Request;
string staffid = request.Headers.Contains("userid") ? HttpUtility.UrlDecode(request.Headers.GetValues("userid").FirstOrDefault()) : string.Empty;
string timestamp = request.Headers.Contains("timestamp") ? HttpUtility.UrlDecode(request.Headers.GetValues("timestamp").FirstOrDefault()) : string.Empty;
string nonce = request.Headers.Contains("nonce") ? HttpUtility.UrlDecode(request.Headers.GetValues("nonce").FirstOrDefault()) : string.Empty;
string signature = request.Headers.Contains("signature") ? HttpUtility.UrlDecode(request.Headers.GetValues("signature").FirstOrDefault()) : string.Empty; if (String.IsNullOrEmpty(staffid) || String.IsNullOrEmpty(timestamp) || String.IsNullOrEmpty(nonce) || String.IsNullOrEmpty(signature))
{
//令牌检验不通过
actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
return;
}
else
{
//令牌检验token失效
if (HttpRuntime.Cache.Get(staffid) == null)
{
actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
return;
}
else
{
//停牌检验2:判断timespan是否失效
Token token = (Token)HttpRuntime.Cache.Get(staffid);
double ts1 = ;
bool timespanvalidate = double.TryParse(timestamp, out ts1);
double ts2 = (token.ExpireTime - new DateTime(, , , , , , )).TotalSeconds;
bool flag = (ts2 - ts1) > token.Seconds ? true : false;
bool tokenFlag = (token.SignToken.ToString() == signature) ? true : false;
if (timespanvalidate && (!flag) && tokenFlag)
{
//时间转换成功、时间有效、token值相等
//令牌通过
base.OnActionExecuting(actionContext);
return;
}
else
{
actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
return;
}
}
}
}
} }
}

6       编写.NET WebApi的服务端

UserController.cs

using System;
using System.Net;
using System.Web.Http; namespace SSLWebApi.Controllers
{
[RoutePrefix("api/User")]
public class UserController : ApiController
{
/// <summary>
/// 获取当前用户信息
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
[HttpPost]
[Route("PostMessage")]
public string PostMessage(dynamic obj)
{
return string.Format("当前输入的消息是:{0}", Convert.ToString(obj.msg));
} [Route("GetMachine")]
public string GetMachine()
{
string AddressIP = string.Empty;
foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
{
if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
{
AddressIP = _IPAddress.ToString();
}
}
return string.Format("当前WebApi部署的IP是:{0}", AddressIP);
}
}
}

7       编写.NET WebApi的客户端

WebApiHelper.cs

using Newtonsoft.Json;
using System;
using System.IO;
using System.Net;
using System.Text; namespace SSLWebApiClient.Common
{
public class WebApiHelper
{
/// <summary>
/// Post请求
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="url">url</param>
/// <param name="data">数据</param>
/// <param name="userid">帐户</param>
/// <param name="signature">数字签名</param>
/// <returns></returns>
public static string Post(string url, string data, string userid, string signature)
{
return PostData(url, data, userid, signature);
} /// <summary>
/// Post请求
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="url">url</param>
/// <param name="data">数据</param>
/// <param name="userid">帐户</param>
/// <param name="signature">数字签名</param>
/// <returns></returns>
public static T Post<T>(string url, string data, string userid, string signature)
{
return JsonConvert.DeserializeObject<T>(Post(url, data, userid, signature));
} /// <summary>
///
/// </summary>
/// <param name="webApi"></param>
/// <param name="queryStr"></param>
/// <param name="userid"></param>
/// <param name="signature"></param>
/// <returns></returns>
public static string Get(string webApi, string queryStr, string userid, string signature)
{
return GetData(webApi, queryStr, userid, signature);
} /// <summary>
/// Get请求
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="webApi"></param>
/// <param name="query"></param>
/// <param name="queryStr"></param>
/// <param name="userid"></param>
/// <param name="signature"></param>
/// <returns></returns>
public static T Get<T>(string webApi, string queryStr, string userid, string signature)
{
return JsonConvert.DeserializeObject<T>(GetData(webApi, queryStr, userid, signature));
} /// <summary>
/// 获取时间戳
/// </summary>
/// <returns></returns>
private static string GetTimeStamp()
{
TimeSpan ts = DateTime.Now - new DateTime(, , , , , , );
return ts.TotalSeconds.ToString();
} /// <summary>
/// 获取随机数
/// </summary>
/// <returns></returns>
private static string GetRandom()
{
Random rd = new Random(DateTime.Now.Millisecond);
int i = rd.Next(, int.MaxValue);
return i.ToString();
}
/// <summary>
/// Post请求
/// </summary>
/// <param name="url"></param>
/// <param name="data"></param>
/// <param name="userid">用户名称</param>
/// <param name="signature">数字签名</param>
/// <returns></returns>
private static string PostData(string url, string data, string userid, string signature)
{
try
{
byte[] bytes = Encoding.UTF8.GetBytes(data);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); string timeStamp = GetTimeStamp();
string nonce = GetRandom();
//加入头信息
//当前请求用户
request.Headers.Add("userid", userid);
//发起请求时的时间戳(单位:秒)
request.Headers.Add("timestamp", timeStamp);
//发起请求时的时间戳(单位:秒)
request.Headers.Add("nonce", nonce);
//当前请求内容的数字签名
request.Headers.Add("signature", signature); //写数据
request.Method = "POST";
request.ContentLength = bytes.Length;
request.ContentType = "application/json";
request.GetRequestStream().Write(bytes, , bytes.Length);
//读数据
request.Timeout = ;
request.Headers.Set("Pragma", "no-cache");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream streamReceive = response.GetResponseStream();
StreamReader streamReader = new StreamReader(streamReceive, Encoding.UTF8);
string strResult = streamReader.ReadToEnd(); //关闭流
//reqstream.Close();
streamReader.Close();
streamReceive.Close();
request.Abort();
response.Close();
return strResult;
}
catch (Exception ex)
{
return ex.Message;
}
} /// <summary>
/// Get请求
/// </summary>
/// <param name="webApi"></param>
/// <param name="queryStr"></param>
/// <param name="userid"></param>
/// <param name="signature"></param>
/// <returns></returns>
private static string GetData(string webApi, string queryStr, string userid, string signature)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(webApi + "?" + queryStr);
string timeStamp = GetTimeStamp();
string nonce = GetRandom();
//加入头信息
//当前请求用户
request.Headers.Add("userid", userid);
//发起请求时的时间戳(单位:秒)
request.Headers.Add("timestamp", timeStamp);
//发起请求时的时间戳(单位:秒)
request.Headers.Add("nonce", nonce);
//当前请求内容的数字签名
request.Headers.Add("signature", signature); request.Method = "GET";
request.ContentType = "application/json";
request.Timeout = ;
request.Headers.Set("Pragma", "no-cache");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream streamReceive = response.GetResponseStream();
StreamReader streamReader = new StreamReader(streamReceive, Encoding.UTF8);
string strResult = streamReader.ReadToEnd(); streamReader.Close();
streamReceive.Close();
request.Abort();
response.Close();
return strResult;
}
catch (Exception ex)
{
return ex.Message;
}
} }
}

Program.cs

using System;
using System.IO;
using System.Net;
using System.Text;
using Newtonsoft.Json;
namespace SSLWebApiClient
{
class Program
{
static void Main(string[] args)
{
string basicUrl = "http://localhost:20107";
string html = string.Empty;
for (int i = ; i < ; i++)
{
//https协议基本认证 Authorization
string url = basicUrl + "/api/base/Login?userId=zhyongfeng";
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
NetworkCredential credential = new NetworkCredential("zhyongfeng", "");
req.Credentials = credential;
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8);
html = streamReader.ReadToEnd().Replace("\"", "");
Console.WriteLine("Token服务器保存时间为12s");
Console.WriteLine(String.Format("服务器返回的Token值为:{0}", html));
}
//token设置了12s有效期
for (int j = ; j < ; j++)
{
System.Threading.Thread.Sleep();
string url = basicUrl + "/api/user/PostMessage";
Console.WriteLine(Common.WebApiHelper.Post(url, JsonConvert.SerializeObject(new { msg = "hello" }), "zhyongfeng", html));
}
for (int j = ; j < ; j++)
{
System.Threading.Thread.Sleep();
string url = basicUrl + "/api/user/GetMachine";
Console.WriteLine(Common.WebApiHelper.Get(url, null, "zhyongfeng", html));
}
Console.Read();
} }
}

8       部署WebApi到局域网内3台PC机

将WebApi部署到以下10.92.202.56的3台PC机

9       Nginx集群配置搭建

通过自主义域名zhyongfeng.com:80端口进行负载均衡集群访问,则访问C:\Windows\System32\drivers\etc\hosts,添加下列“本机IP 自定义的域名”:

10.93.85.66     zhyongfeng.com

Nginx的集群配置:

#user  nobody;
worker_processes 1;
events {
worker_connections 1024;
} http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
#server {
# listen 80;
# server_name localhost;
# location / {
# root html;
# index index.html index.htm;
# }
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# root html;
# }
#} upstream zhyongfeng.com {
server 10.92.202.56:560;
server 10.92.202.57:570;
server 10.92.202.58:580;
}
server {
listen 80;
server_name zhyongfeng.com;
rewrite ^(.*)$ https://$host$1 permanent;
}
# HTTPS server
#
server {
listen 443 ssl;
server_name zhyongfeng.com;
ssl_certificate server.crt;
ssl_certificate_key server_nopass.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
location / {
proxy_pass http://zhyongfeng.com;
}
}
}

运行CMD:

D:\DTLDownLoads\nginx-1.10.2>start nginx

D:\DTLDownLoads\nginx-1.10.2>nginx -s reload

10             运行结果

因只有其中一台计算生成了相应的Token值(这里只做其中一台,如果要三台都能够响应,可以用redis做相应的Token值存储)

其中一台10.92.202.58生成了Token值,运行结果如下:

  • 访问指定的http://10.92.202.56:560

因Token值设定了12s后失效,则返回“远程服务器返回错误:<403>已禁止”,运行效果如下:

11             总结

Nginx基于SSL协议下,客户端利用 http basic身份验证,访问WebApi获得Token,通过Token值获取相应的权限数据,使系统的安全性有了保障,同时灵活运用Token身份令牌,可以实现时效性的数据访问。基于Token的身份验证,针对前后端分离有着很大的作用。例如手机移动端、平板电脑。

源代码下载:

http://download.csdn.net/download/ruby_matlab/10146669

PDF下载:

Nginx集群之SSL证书的WebApi令牌验证.pdf

Nginx集群之SSL证书的WebApi令牌验证的更多相关文章

  1. Nginx集群之SSL证书的WebApi身份验证

    目录 1       大概思路... 1 2       Nginx集群之SSL证书的WebApi身份验证... 1 3       AuthorizeAttribute类... 2 4       ...

  2. Nginx集群之SSL证书的WebApi微服务

    目录 1       大概思路... 1 2       Nginx集群之SSL证书的WebApi微服务... 1 3       HTTP与HTTPS(SSL协议)... 1 4       Ope ...

  3. Nginx集群之基于Redis的WebApi身份验证

    目录 1       大概思路... 1 2       Nginx集群之基于Redis的WebApi身份验证... 1 3       Redis数据库... 2 4       Visualbox ...

  4. 扎实基础之从零开始-Nginx集群分布式.NET应用

    1       扎实基础之快速学习Nginx Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行.其特点是占有内存少 ...

  5. Nginx集群之WCF分布式身份验证(支持Soap)

    目录 1       大概思路... 1 2       Nginx集群之WCF分布式身份验证... 1 3       BasicHttpBinding.ws2007HttpBinding. 2 4 ...

  6. linux 下nginx 集群CAS单点登录实现

    1.单点登录服务器CAS应用配置于tomcat下. 1)key生成: keytool -genkey -alias mycas -keyalg RSA -keysize 2048 -keystore ...

  7. Nginx集群之.Net打造WebApp(支持IOS和安卓)

    目录 1       大概思路... 1 2       Nginx集群之.Net打造WebApp(支持IOS和安卓) 1 3       安卓模拟器... 1 4       MUI框架... 3 ...

  8. nginx 集群介绍

    nginx 集群介绍 完成一次请求的步骤 1)用户发起请求 2)服务器接受请求 3)服务器处理请求(压力最大) 4)服务器响应请求 缺点:单点故障 单台服务器资源有限 单台服务器处理耗时长 ·1)部署 ...

  9. 庐山真面目之十微服务架构 Net Core 基于 Docker 容器部署 Nginx 集群

    庐山真面目之十微服务架构 Net Core 基于 Docker 容器部署 Nginx 集群 一.简介      前面的两篇文章,我们已经介绍了Net Core项目基于Docker容器部署在Linux服 ...

随机推荐

  1. Windows下Tomcat调优

    windows tomcat 优化 1.  tomcat conf server.xml 在server.xml中修改以一部分,增加节点数目,可以很好的提高性能: <Connector port ...

  2. java微信开发API解析(二)-获取消息和回复消息

    java微信开发API解析(二)-获取消息和回复消息 说明 * 本演示样例依据微信开发文档:http://mp.weixin.qq.com/wiki/home/index.html最新版(4/3/20 ...

  3. duilib 快捷键发送消息

    全局快捷键设置类,文章最以下,有3种不同的使用方法(假设设置的快捷键,与其它软件的快捷键同样.那么仅仅有你的程序起作用.你释放后它才干够使用) .h文件 #pragma once class CHot ...

  4. SharePoint 2013 引发类型为“System.ArgumentException”的异常。 參数名: encodedValue

    SharePoint 2013 引发类型为"System.ArgumentException"的异常. 參数名: encodedValue 具体错误信息 说明: 运行当前 Web ...

  5. NBUT 1217 Dinner

    [1217] Dinner 时间限制: 1000 ms 内存限制: 32768 K 问题描写叙述 Little A is one member of ACM team. He had just won ...

  6. HDU1598 find the most comfortable road 【并查集】+【枚举】

    find the most comfortable road Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K ...

  7. 蓝牙核心技术概述(五):蓝牙协议规范(irOBEX、BNEP、AVDTP、AVCTP)

    关键词:蓝牙核心技术协议  irDA BNEP  AVDTP AVCTP 作者:xubin341719(欢迎转载,请注明作者,请尊重版权,谢谢! )欢迎指正错误,共同学习.共同进步!! 下载链接:Bl ...

  8. Python的几个常用模块

    一.sys 用于提供对Python解释器相关的操作: sys.argv 命令行参数List,第一个元素是程序本身路径 sys.exit(n) 退出程序,正常退出时exit(0) sys.version ...

  9. 工作随笔——spring异步处理@Async使用笔记

    @Async使用笔记 必须是public方法 必须是非static方法 方法调用的实例必须由spring创建和管理 代码示例如下: // 创建Foo类@Component class Foo { @A ...

  10. adobe acrobat x pro破解版

    adobe acrobat x pro破解版是Adobe官方出品的PDF文档全能解决方案套件. PDF文件格式是Adobe公司设计的,用其公司开发的Adobe Acrobat X Pro来创建.编辑. ...