使用签名获取Token

首先我们自定义appkey、appSecret。可用GUID随机生成,AppSecret要不定期更换。然后放到配置文件中。

Appkey=1AF62C68-B970-46E7-B545-E5A5712249D4

AppSecret=DA2502F8-626A-405D-90DB-0351A086FE49

WebApI端MD5签名

    public class AuthorizationHelper
{
public static bool CheckPartner(HttpRequestBase request, string appSecret,out string msg)
{
NameValueCollection getCollection = request.Params;//此签名要求Partner及Sign均通过QueryString传递
if (getCollection == null || getCollection.Count == )
{
msg = "调用失败";
return false;
}
string appkey = getCollection["appkey"];
string sign = getCollection["sign"];
string timestamp = getCollection["timestamp"];
bool valid=!string.IsNullOrWhiteSpace(appkey)//必须包含partner
&& !string.IsNullOrWhiteSpace(sign)//必须包含sign
&& !string.IsNullOrWhiteSpace(timestamp)//必须包含timestamp
&& Regex.IsMatch(appkey, "^[0-9A-Za-z]{32}$")//appkey必须为32位
&& Regex.IsMatch(timestamp, "^(((20[0-3][0-9]-(0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|(20[0-3][0-9]-(0[2469]|11)-(0[1-9]|[12][0-9]|30))) (20|21|22|23|[0-1][0-9]):[0-5][0-9]:[0-5][0-9])$")//timestamp格式必须是yyyy-MM-dd hh:mm:ss
&& Regex.IsMatch(sign, "^[0-9A-Za-z]{32}$");//sign必须为32位Md5摘要 if (valid)
{
if (!string.IsNullOrWhiteSpace(appSecret))
{
//根据请求数据获取MD5签名
string vSign = Util.Md5(appkey, appSecret, timestamp);
if (string.Equals(sign, vSign, StringComparison.OrdinalIgnoreCase))
{ var requestDatetime=Convert.ToDateTime(timestamp);
var span= DateTime.Now.Subtract(requestDatetime);
if (Math.Abs(span.TotalMinutes) > )//超过20分钟的请求就过期
{
msg="非法调用,请求过期!";
return false;
}
msg = "调用成功";
return true;
}
}
}
msg = "调用失败";
return false;
} public static bool CheckPartner(string appkey,string sign,string timestamp, string appSecret, out string msg)
{
bool valid = !string.IsNullOrWhiteSpace(appkey)//必须包含partner
&& !string.IsNullOrWhiteSpace(sign)//必须包含sign
&& !string.IsNullOrWhiteSpace(timestamp)//必须包含timestamp
&& Regex.IsMatch(appkey, "^[0-9A-Za-z]{32}$")//appkey必须为32位
&& Regex.IsMatch(timestamp, "^(((20[0-3][0-9]-(0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|(20[0-3][0-9]-(0[2469]|11)-(0[1-9]|[12][0-9]|30))) (20|21|22|23|[0-1][0-9]):[0-5][0-9]:[0-5][0-9])$")//timestamp格式必须是yyyy-MM-dd hh:mm:ss
&& Regex.IsMatch(sign, "^[0-9A-Za-z]{32}$");//sign必须为32位Md5摘要 if (valid)
{ if (!string.IsNullOrWhiteSpace(appSecret))
{
//根据请求数据获取MD5签名
string vSign = Util.Md5(appkey, appSecret, timestamp);
if (string.Equals(sign, vSign, StringComparison.OrdinalIgnoreCase))
{
var requestDatetime=Convert.ToDateTime(timestamp);
var span= DateTime.Now.Subtract(requestDatetime);
if (Math.Abs(span.TotalMinutes) > )//超过10分钟的请求就过期
{
msg="非法调用,请求过期!";
return false;
}
msg = "调用成功";
return true;
}
}
}
msg = "调用失败";
return false;
}
}

WebApi端生成token

    public class BasePrincipal
{
/// <summary>
/// 用户Id
/// </summary>
public int Id { get; set; }
/// <summary>
/// 手机号
/// </summary>
public string Phone { get; set; }
/// <summary>
/// token
/// </summary>
public string Token { get; set; }
/// <summary>
/// 有效期(秒)
/// </summary>
public int Expires { get; set; }
/// <summary>
/// 消息
/// </summary>
public string Message { get; set; } } public class HomeController : Controller
{
/// <summary>
/// Redis帮助类
/// </summary>
static readonly RedisHelper redisHelper = new RedisHelper(); [AllowAnonymous]
public JsonResult Login()
{
BasePrincipal result = new BasePrincipal();
string token = Request.Headers["token"];
var key = "Login:token:";
if (!string.IsNullOrEmpty(token)) //有token,取redis
{
key=$"{key}{token}";
result = redisHelper.StringGet<BasePrincipal>(key);
if (result != null)
{
return new JsonResult() { Data = result, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
} var phone = Request.Params["phone"];
if (phone == null)
{
result.Message = "缺少手机号";
return new JsonResult(){Data = result, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
} var msg = "";
var AppSecret = System.Configuration.ConfigurationManager.AppSettings["AppSecret"];
var isAuthorization = AuthorizationHelper.CheckPartner(Request, AppSecret, out msg);
if (!isAuthorization)
{
result.Message = $"检验不成功,{0},msg";
return new JsonResult(){Data = result, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
//获取用户信息业务,各位根据业自己实现这行代码
result = personService.LoginPersonInfo(phone);
if (result == null)
{
result.Message = "用户不存在";
return new JsonResult(){Data = result, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
} token = Guid.NewGuid().ToString("N");//生成token
result.Token = token;
result.Expires = * * ;
//设置redis
key = $"{key}{token}";
redisHelper.StringSet(key, result,TimeSpan.FromSeconds(result.Expires));
return new JsonResult(){Data = result, JsonRequestBehavior = JsonRequestBehavior.AllowGet }; }
}

WebApi在Global.asax.cs端校验token

    public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles); } void Application_BeginRequest(object sender, EventArgs e)
{
//Cors跨域设置(这些配制放在HttpMethod=="OPTIONS"里面就调用出错,放出来就没事,不知原因)
var response = HttpContext.Current.Response;
response.AddHeader("Access-Control-Allow-Origin", "*"); //正式环境注意改成具体网站,*代表允许所有网站
response.AddHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
response.AddHeader("Access-Control-Allow-Headers", "Content-Type,token,Authorization");//Content-Type
response.AddHeader("Access-Control-Max-Age", "");//设置跨域缓存,减少浏览器OPTIONS访问次数 if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
response.End();
}
} protected void Application_Error(object sender, EventArgs e)
{
//获取到HttpUnhandledException异常,这个异常包含一个实际出现的异常
Exception ex = Server.GetLastError();
//实际发生的异常
Exception innerException = ex.InnerException;
if (innerException != null) ex = innerException; HttpContext.Current.Response.Write(string.Format("捕捉到未处理的异常:{0}<br/>", ex.GetType().ToString()));
HttpContext.Current.Response.Write("Global已进行错误处理。<br/>");
HttpContext.Current.Response.Write(string.Format("Exception:{0}", ex)); Server.ClearError();
} void Application_PostAuthenticateRequest(object sender, EventArgs e)
{ // 如果是header中token认证
if (Request.Headers["token"] != null)
{
var token = Request.Headers["token"];
if (!string.IsNullOrEmpty(token))
{
var key = $"Login:token:{token}";
RedisHelper redisHelper = new RedisHelper();
var user = redisHelper.StringGet<BasePrincipal>(key);
if (user != null)
{
HttpContext.Current.User = new PersonPrincipal(user);
return;
}
}
} HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName]; if (authCookie != null)
{
var url = HttpContext.Current.Request.Url.ToString();
if (!string.IsNullOrEmpty(url) && url.StartsWith("https"))
{
authCookie.Secure = true;
}
BasePrincipal clientUserData = null;
try
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
if (authTicket != null)
clientUserData = JsonConvert.DeserializeObject<BasePrincipal>(authTicket.UserData);
}
catch
{
// ignored
} if (HttpContext.Current != null && clientUserData != null)
{
HttpContext.Current.User = new PersonPrincipal(clientUserData);
}
}
} protected void Application_End()
{
} }

WebApi 配置文件中加入authentication等节点

<system.web>
<authentication mode="Forms">
<forms name=".testToken" loginUrl="url" timeout="" protection="All" defaultUrl="index.html" />
</authentication>
<compilation debug="true" targetFramework="4.6.2" />
<httpRuntime targetFramework="4.5" maxRequestLength="" executionTimeout="" />
<customErrors mode="Off" />
<globalization culture="zh-cn" uiCulture="zh-CHS" />
<sessionState mode="Off"></sessionState>
<httpCookies httpOnlyCookies="true" requireSSL="true" />
</system.web>

客户端签名后调用WebApi Login方法获取token

public BasePrincipal GetToken(string phone)
{
var appkey = System.Configuration.ConfigurationManager.AppSettings["Appkey"];
var appSecret = System.Configuration.ConfigurationManager.AppSettings["AppSecret"];
var webApi_url = System.Configuration.ConfigurationManager.AppSettings["WebApi_url"]; var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); #region sign
string[] inputs = new string[] { appkey, appSecret, timestamp };
Array.Sort(inputs);//排序
string tmpStr = string.Join("", inputs);
var md5Hash = new System.Security.Cryptography.MD5CryptoServiceProvider();
var data = md5Hash.ComputeHash(System.Text.Encoding.UTF8.GetBytes(tmpStr));
var sBuilder = new System.Text.StringBuilder();
foreach (var t in data)
{
sBuilder.Append(t.ToString("x2"));
} var sign = sBuilder.ToString();
#endregion var url = string.Format(webApi_url + "/Home/Login?appkey={0}&timestamp={1}&sign={2}&phone={4}", appkey, timestamp, sign, phone); var result = HttpClientManager.GetResponse<BasePrincipal>(url); if (result != null)
{
return result;
} return null;
}

将获取到的token保存在客户端中,在调用webapi接口时,把token放到header中

function GetPerson(phone) {
let token = localStorage.getItem("token");
$.ajax({
url: 'http://*******/api/Person/GetPerson,
data: {
phone: phone
},
beforeSend: function (request) {
request.setRequestHeader("token", token);
},
dataType: 'JSON',
async: false,//请求是否异步,默认为异步
type: 'GET',
success: function (list) {
},
error: function () {
}
});
}

Web API的接口访问安全性的更多相关文章

  1. 基于ASP.NET WEB API实现分布式数据访问中间层(提供对数据库的CRUD)

    一些小的C/S项目(winform.WPF等),因需要访问操作数据库,但又不能把DB连接配置在客户端上,原因有很多,可能是DB连接无法直接访问,或客户端不想安装各种DB访问组件,或DB连接不想暴露在客 ...

  2. Web Api跨域访问配置及调用示例

    1.Web Api跨域访问配置. 在Web.config中的system.webServer内添加以下代码: <httpProtocol> <customHeaders> &l ...

  3. 适用于app.config与web.config的ConfigUtil读写工具类 基于MongoDb官方C#驱动封装MongoDbCsharpHelper类(CRUD类) 基于ASP.NET WEB API实现分布式数据访问中间层(提供对数据库的CRUD) C# 实现AOP 的几种常见方式

    适用于app.config与web.config的ConfigUtil读写工具类   之前文章:<两种读写配置文件的方案(app.config与web.config通用)>,现在重新整理一 ...

  4. ASP.NET Web API 跨域访问(CORS)

    一.客户端用JSONP请求数据 如果你想用JSONP来获得跨域的数据,WebAPI本身是不支持javascript的callback的,它返回的JSON是这样的: {"YourSignatu ...

  5. Web Api 2 接口API文档美化

    使用用第三方提供的swgger ui 帮助提高 web api 接口列表的阅读性,并且可以在页面中测试服务接口. 运行程序如下: 注意:在IE中必须输入红色部分. 并且可以对方法进行测试. 在开发we ...

  6. 使用swagger实现web api在线接口文档

    一.前言 通常我们的项目会包含许多对外的接口,这些接口都需要文档化,标准的接口描述文档需要描述接口的地址.参数.返回值.备注等等:像我们以前的做法是写在word/excel,通常是按模块划分,例如一个 ...

  7. .NET Core WEB API中接口参数的模型绑定的理解

    在.NET Core WEB API中参数的模型绑定方式有以下表格中的几种: 微软官方文档说明地址:https://docs.microsoft.com/zh-cn/aspnet/core/web-a ...

  8. ASP.NET Web Api 2 接口API文档美化之Swagger

    使用第三方提供的swgger ui 可有效提高 web api 接口列表的阅读性,并且可以在页面中测试服务接口. 但本人在查阅大量资料并进行编码测试后,发现大部分的swagger实例并不能有效运行.例 ...

  9. 使用swagger实现web api在线接口文档(转载)

    一.前言 通常我们的项目会包含许多对外的接口,这些接口都需要文档化,标准的接口描述文档需要描述接口的地址.参数.返回值.备注等等:像我们以前的做法是写在word/excel,通常是按模块划分,例如一个 ...

随机推荐

  1. Ubuntu16.04下ZeroC ICE的安装与使用示例(Qt C++ 和 Java)

    项目需求:在Ubuntu16.04系统下安装并使用ICEgrid 3.7进行c++和Java Springboot开发环境的通信,下面逐一介绍各个步骤的详解: 一:Ice Lib的安装 参考官网地址: ...

  2. 在Java中用 . 深层访问JSON数据

    本文介绍Java中解析JSON的一种方法,可以让我们在Java程序中也用x.x.x的形式访问JSON数据中的值. 代码大部分来源非本人,本人在源代码基础上加以修改以使正常运行. 代码: // 将提取方 ...

  3. python 将汉字转换为拼音

    xpinyin提供把汉字转为汉语拼音的功能. 安装此模块 pip install xpinyin简单用例: from xpinyin import Pinyin pin = Pinyin() test ...

  4. .Net memory management Learning Notes

    Managed Heaps In general it can be categorized into 1) SOH and 2) LOH.  size lower than 85K will be ...

  5. 工具提高效率 - iterm2

    快捷键 command + d, command + shift +d 显示所有记录 ITERM默认设置了终端能保留的历史输出行数,在进行调试时特别不方便,一旦输出过多就无法看到完整的历史记录. 在P ...

  6. ubuntu下使用opencv问题以及解决方案

    CMakeFiles/hw5_1_node.dir/computeORB.o: In function `cv::String::~String()':/usr/local/include/openc ...

  7. 20175120彭宇辰 《Java程序设计》第六周学习总结

    教材学习内容总结 第七章 一.内部类与外部类的关系 1.内部类可以使用外嵌类的成员变量和方法.2.类体中不可以声明类变量和类方法,外部类可以用内部类声明对象.3.内部类仅供外嵌类使用.4.类声明可以使 ...

  8. vs code 操作Git

    首次从Git拉取项目:Ctrl+Shift+p 选择Git 克隆 拉取成功后 Ctrl+波浪号进入控制台选择终端 使用npm install下载依赖 到此就从Git拉取成功了: 如果提示npm错误,有 ...

  9. 实验六 CC2530平台上P2P通信的TinyOS编程

    实验六 CC2530平台上P2P通信的TinyOS编程 实验目的: 加深和巩固学生对于TinyOS编程方法的理解和掌握 让学生初步的掌握射频通信TinyOS编程方法 学生通过本实验应理解TinyOS中 ...

  10. 4th week——grid-layout