使用签名获取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. CentOS Linux 升级内核步骤和方法(转)

    当前系统为CentOS Linux release 6.0 (Final),内核版本为2.6.32-71.el6.i686.由于最近内核出现最新的漏洞(linux kernel 又爆内存提权漏洞,2. ...

  2. thinkphp5.0如何隐藏index.php入口文件

    隐藏入口文件 public/index.php 同级的.htaccess文件 [ Apache ] 方法1: <IfModule mod_rewrite.c> Options +Follo ...

  3. windows下启动mysql服务

    当你无法连接你的mysql数据库时,或者因为某些原因导致与mysql数据库的连接丢失时,可通过以下方式启动mysql服务 1.命令行下启动mysql服务 以管理员身份运行cmd,进入mysql安装目录 ...

  4. AssetBundle打包-----BuildPipeline的应用

    打包思路:确定要打包资源的路径.和打包的输出路径(一般为S路径),把存放资源的路径使用递归进行遍历,获取所有资源,文件类型的资源可以通过File拷贝或IO写到输出路径,其他资源的打包通过AssetBu ...

  5. 关于 API

    1. API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访 ...

  6. linx6.7 update openssh to 7.7p1

    升级之前需要注意几点: 1 必须要有自己的镜像,必须自己做好本地yum源(可以连接外网,能够有网络yum源也可以) 2 配置好基本的升级环境.在升级openssh时需要依赖openssl和zlib.一 ...

  7. 常识判断-科技-day123

    PS: 在常识中科技是最难的 PS: 20-2w  HZ是人能听到的频率 PS: 物体的熔点和凝固点是一致的 PS: 氮肥如果多了,可能只是长叶子不结果: 磷肥促进开花结果 PS; 病毒是介于生物和非 ...

  8. visual studio 2017 创建 android 本地共享库(.so) 并从 C# android 项目中调用

    Developing Xamarin Android Native Applications ★★★★★ ★★★★ ★★★ ★★ ★ February 23, 2015 by Ankit Asthan ...

  9. bootstrap简单使用实例

    表格实例,包含bootstrap.css 和 2.1.1jquery <!DOCTYPE html> <html> <head> <meta charset= ...

  10. java8_api_jni

    java本地接口    jni    java native interface,用于java代码和本地编程语言(c,c++等)交互的编程接口    java不太会跟底层硬件打交道,而c,c++跟底层 ...