使用签名获取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. ChIP-seq基本流程及工具

    ChIP-seq数据分析整理 1.Alignment 2.Peak detection 3.Peak annotation 1. GO analysis 2. Pathway analysis 4.D ...

  2. 【oracle入门】SQL的命令动词

      SQL的功能 命令动词 数据定义 CREATE,DROP,ALTER 数据操纵 SELECT,INSERT,UPDATE,DELETE 数据控制 CRANT,REVOKE

  3. linux nginx 如何配置多个端口

    在linux下发布.netcore 应用,并使用nginx进行反向代理,参照博客园文章 https://www.cnblogs.com/ants/p/5732337.html#autoid-7-3-0 ...

  4. [LeetCode&Python] Problem 70. Climbing Stairs

    You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb ...

  5. Python IO密集型任务、计算密集型任务,以及多线程、多进程

    对于IO密集型任务: 直接执行用时:10.0333秒 多线程执行用时:4.0156秒 多进程执行用时:5.0182秒 说明多线程适合IO密集型任务. 对于计算密集型任务 直接执行用时:10.0273秒 ...

  6. 小程序swiper指板点样式修改

    swiper(class名).wx-swiper-dots.wx-swiper-dots-horizontal{    //距离底部高度 margin-bottom: 2rpx; } swiper(c ...

  7. Hibernate 相关配置

    hibernate.temp.use_jdbc_metadata_defaults 它是用来控制是否应该向JDBC元数据来确定某些设置默认值,在数据库某些服务不可用的设置为 *不*,在某些工具中开发是 ...

  8. javaWeb-Servlet工作原理

    1.客户发出请求—>Web 服务器转发到Web容器Tomcat: 2.Tomcat主线程对转发来用户的请求做出响应创建两个对象:HttpServletRequest和HttpServletRes ...

  9. 第3章 Data语意学

    在C++中经常会遇到一个类的大小问题,关于一个类的大小一般受到三个方面的影响. 语言本身所造成的额外负担,如在虚拟继承中会遇到如派生类中会包含一个指针指向base class subobjec,这样会 ...

  10. EXCEL日期格式要双击一下单元格才变正确格式

    今天遇到标题问题,问度娘后看到一个大神的解答,特此记录整理. 步骤1:在excel中把文本格式日期改为想要的日期格式 步骤2:在旁边空格中输入1,并设置成日期格式,变成1900/1/1: 步骤3:复制 ...