目录

1       大概思路... 1

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

3       Redis数据库... 2

4       Visualbox虚拟机ubuntu下的redis部署... 3

5       编写.NET WebApi的OnAuthorization身份验证... 6

6       编写.NET WebApi的ActionFilterAttribute令牌验证... 8

7       编写.NET WebApi的服务端... 10

8       编写.NET WebApi的客户端... 11

9       部署WebApi到本机... 17

10     Nginx集群配置搭建... 18

11     运行结果... 19

12     总结... 20

1       大概思路

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

l  Redis数据库

l  Visualbox虚拟机ubuntu下的redis部署

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

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

l  编写.NET WebApi的服务端

l  编写.NET WebApi的客户端

l  部署WebApi到本机

l  Nginx集群配置搭建

l  运行结果

l  总结

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

Nginx在集群上使用Redis数据库进行身份验证,达到了支持集群、分布式。在此基础上能够实现单点登录、时效性的访问,结合WebApi最大限度地发挥了后台身份验证的管理。

基于Redis的原因有几个:第一点是Redis是基于内存的数据库访问起来比较快,能够设置数据库存储的时效性;第二点,Redis数据库的语法比较简单、轻巧,在Linux、Windows服务器均可以一键安装完成;第三点,Redis支持数据的备份,即master-slave模式的数据备份。

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

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

Token令牌身份验证机制:

Nginx集群之基于Redis的WebApi身份验证,如下图所示:

3       Redis数据库

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Map), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。

具体可以在以下网址进行学习:

http://www.runoob.com/redis/redis-tutorial.html

4       Visualbox虚拟机ubuntu下的redis部署

(已安装Oracle VM VirtualBox、ubuntu-17.10-desktop-amd64.iso)

Redis安装可参考:http://www.runoob.com/redis/redis-install.html

  • 虚拟机

因网络的限制,本文采取的是“网络地址转换(NAT)”方式,进行redis数据库连接访问。有条件的可以采用“桥接网上”的方式,便可以使多台PC机在同一redis数据库进行访问,达到集群的效果。

Linux的ubuntu打开6379端口:

sudo iptables -I INPUT -p tcp --dport 6379 -j ACCEPT

具体如下所示:

登录Redis服务器,设置密码:

redis-cli
config set requirepass 123456

  • 主机

Windows安装Telnet客户端,进行测试连接成功与否

运行CMD,输入命令行如下:

Microsoft Windows [版本 6.1.7601]
版权所有 (c) 2009 Microsoft Corporation。保留所有权利。C:\Users\zhyongfeng>telnet 10.93.85.66 6379

测试成功

5       编写.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", "123456"))){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 ServiceStack.Redis;
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 = 12;token.ExpireTime = DateTime.Now.AddSeconds(token.Seconds);//redis使用sudo iptables -A INPUT -p tcp --dport 6379 -j ACCEPT打开6379的端口//visualbox虚拟机使用“设置->网络->高级->端口转发”创建商品规则//连接远程visualbox虚拟机ubtuntu的redis,形成一个分布式的登录验证string remoteIp = "10.93.85.66";int remotePort = 6379;string remoteDbPassword = "123456";//RedisClient(地址,端口,密码,0)using (var client = new RedisClient(remoteIp, remotePort, remoteDbPassword, 0)){string strToken = token.SignToken.ToString();if (client.Exists(userId) > 0)client.Del(userId);if (client.Add(userId, strToken)){//设置key的过期时间为12sclient.Expire(userId, 12);return token.SignToken.ToString();}elsereturn string.Format("远程虚拟机{0}的redis创建token失败", remoteIp);}}}
}

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

WebApiSecurityFilter.cs

using ServiceStack.Redis;
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"){//登录成功则生成tokenbase.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{string remoteIp = "10.93.85.66";int remotePort = 6379;string remoteDbPassword = "123456";using (var client = new RedisClient(remoteIp, remotePort, remoteDbPassword, 0)){//令牌检验是否存在这个用户if (client.Exists(staffid) > 0){string tempStr = System.Text.Encoding.UTF8.GetString(client.Get(staffid));if (tempStr.Trim('"').Equals(signature)){//时间转换成功、时间有效、token值相等//令牌通过base.OnActionExecuting(actionContext);return;}else{actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);return;}}else{actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);return;}}}}}}
}

7       编写.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);}}
}

8       编写.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(1970, 1, 1, 0, 0, 0, 0);return ts.TotalSeconds.ToString();}/// <summary>  /// 获取随机数/// </summary>  /// <returns></returns>  private static string GetRandom(){Random rd = new Random(DateTime.Now.Millisecond);int i = rd.Next(0, 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, 0, bytes.Length);//读数据request.Timeout = 300000;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 = 90000;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://zhyongfeng.com";string html = string.Empty;for (int i = 0; i < 1; i++){//https协议基本认证 Authorizationstring url = basicUrl + "/api/base/Login?userId=zhyongfeng";ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);NetworkCredential credential = new NetworkCredential("zhyongfeng", "123456");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("Redis Token服务器保存时间为12s");Console.WriteLine(String.Format("Redis服务器返回的Token值为:{0}", html));}//token设置了12s有效期for (int j = 0; j < 5; j++){System.Threading.Thread.Sleep(1000);string url = basicUrl + "/api/user/PostMessage";Console.WriteLine(Common.WebApiHelper.Post(url, JsonConvert.SerializeObject(new { msg = "hello" }), "zhyongfeng", html));}for (int j = 0; j < 10; j++){System.Threading.Thread.Sleep(1000);string url = basicUrl + "/api/user/GetMachine";Console.WriteLine(Common.WebApiHelper.Get(url, null, "zhyongfeng", html));}Console.Read();}}
}

9       部署WebApi到本机

将WebApi部署到以下10.93.85.66(因网络限制,所以这里只做单个集群,虚拟机ubuntu中的数据redis主要是NAT网络连接方式,使用端口转发进行访问)

10             Nginx集群配置搭建

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

10.93.85.66     zhyongfeng.com

Nginx的集群配置:

worker_processes  1;
events {worker_connections  1024;
}http {include       mime.types;default_type  application/octet-stream;sendfile        on;keepalive_timeout  65;

upstream zhyongfeng.com {server       10.93.85.66:20107;}server {listen       80;server_name  localhost;location / {proxy_pass   http://zhyongfeng.com;}error_page   500 502 503 504  /50x.html;location = /50x.html {root   html;}}
}

运行CMD:

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

11             运行结果

访问集群:http://zhyongfeng.com

WebApi经过Action过滤器,生成了Token值,并存储到Redis,运行结果如下:

12             总结

Nginx集群使用Redis数据库,客户端利用 http basic身份验证,访问WebApi获得Token并将Token存储到Redis内在数据库,通过Token值获取相应的权限数据,这样子可以做到单点登录,集群分布式的身份验证效果。既方便了用户在整个业务领域的系统操作,同时可以为整个公司、集团等各个区域的系统进行统一有效的身份验证管理。

转载于:https://www.cnblogs.com/sjqq/p/9152726.html

Nginx集群之基于Redis的WebApi身份验证相关推荐

  1. CentOS7下安装Redis伪集群(基于Redis官方Cluster集群模式版本redis-5.0.10)

    文章目录 Redis简介 什么是redis redis的优点 Redis集群都有哪些模式 主从复制(Master-Slave Replication) 哨兵模式(Sentinel) Redis官方 C ...

  2. Redis + Tomcat + Nginx 集群实现 Session 共享

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者 | 蕃薯耀 链接 | www.cnblogs.com/fan ...

  3. k8s redis集群_基于K8S部署redis哨兵集群

    本 文 主 要 内 容 什么是Kubernetes分布式容器管理平台 PaaS平台redis-sentinel集群架构简介 PaaS平台部署redis哨兵集群 redis-sentinel容器测试及验 ...

  4. Redis+Tomcat+Nginx集群实现Session共享,Tomcat Session共享

    转载自  Redis+Tomcat+Nginx集群实现Session共享,Tomcat Session共享 一.Session共享使用tomcat-cluster-redis-session-mana ...

  5. 基于LVS高可用架构实现Nginx集群分流

    Nginx实用插件_踩踩踩从踩的博客-CSDN博客 前言 前面文章介绍Nginx的核心及扩展插件必要的性能优化,以及在nginx中如何实用用https:本篇文章会继续讲解重要的概念 lvs高可用框架, ...

  6. C#session共享+redis_Redis+Tomcat+Nginx集群实现Session共享,Tomcat Session共享

    作者:蕃薯耀 链接:www.cnblogs.com/fanshuyao 一.Session共享使用tomcat-cluster-redis-session-manager插件实现 插件地址见: htt ...

  7. Zookeeper+Hadoop+Hbase+Hive+Kylin+Nginx集群搭建

    Zookeeper+Hadoop+Hbase+Hive+Kylin+Nginx集群搭建 一.虚拟机安装Centos7 1.准备工作 2.centos7安装过程 3.关闭防火墙(关键) 二.安装jdk ...

  8. Keepalived+nginx 集群解决单点故障

    Keepalived+nginx 集群解决单点故障 nginx作为负载均衡器,所有请求都到了nginx服务器,可见nginx处于一个非常重要的位置,如果nginx服务器宕机,那么后台的服务器将无法提供 ...

  9. Docker部署Nginx集群

    背景 Nginx作为负载均衡工具在企业开发中,特别是分布式开发中十分常见,下面来看看腾讯云服务器中在CentOS7.6系统中使用Docker部署Nginx集群的具体步骤 环境 Linux:CentOS ...

  10. redis伪集群安装linux,redis伪集群搭建(亲测无坑)

    一.单机版安装部署,伪集群只需要操作前1-8步即可,再往下浏览找到:二.单机版-伪集群  安装部署继续搭建,如需设置密码参照第10步 1.安装基本工具 yum install -y gcc-c++ v ...

最新文章

  1. php中mkdir()函数的权限问题
  2. 字节跳动AI Lab社招以及实习生内推
  3. linux 编译器错误,linux – GHCi – Haskell编译器错误 – /home/user/.ghci归其他人所有,IGNORING...
  4. python语法基础知识总结-Python基础知识梳理 - 第01部分
  5. JavaScript原型学习
  6. Laravel开发:Laravel核心——Ioc服务容器源码解析(服务器绑定)
  7. 从零开始写项目第七篇【搭建Linux环境】
  8. 周末狂欢赛3(跳格子,英雄联盟,排序问题)
  9. CCKS 2018 | 最佳论文:南京大学提出 DSKG,将多层 RNN 用于知识图谱补全
  10. 经验3-5年的测试人,如果还是长期加班、薪资涨幅不大,建议认真看看
  11. C和指针---读书笔记9
  12. 数据结构和算法——中序线索化二叉树
  13. 日本铁路“猫站长”走红
  14. 擦黑板特效表白H5源码+非常浪漫/附BGM
  15. ALFA机器视觉深度学习外观检测自学习人工智能软件——ocr字符检测
  16. outlook 发送邮件
  17. Vue开发历程---音乐播放器的继续
  18. 服务器租用价格与哪些因素有关?
  19. 5年400倍增长,Airbnb首位数据科学家揭秘他们到底怎么做的?
  20. 大数据的数据库设计原则有哪些

热门文章

  1. 第二十三模板 1什么是模板
  2. .NET 指南:资源的名称
  3. Android Studio安装、应用与卸载
  4. SVN—如何安装SVN客户端软件
  5. Jquery—Jquery中的(function($){...})(jQuery)
  6. C#正则提取字符串中的数字
  7. jQuery基础资料(三)
  8. 使用脚本 Nodesource快速安装nodejs环境
  9. MySQL的Binlog与Redolog
  10. 浅谈C++中类的const成员变量,static成员变量和const static成员变量的区别