3、Web Api 身份验证
由于接口传递的是企业内部数据,在数据安全性方面需要把控,因此当客户端调用接口时,必须提供身份标识,验证通过之后方可调用接口,以确保数据的安全性。由于WebApi的身份校验是面向切面编程的,即当你需要进行身份校验时,执行逻辑为:Client->Filter身份校验->接口,当校验通过时,即可正常调用
当校验不通过时,将返回401身份验证失败。
一、身份校验 Basic
1、在Api项目下创建Filter文件夹
2、编写验证程序
using System; using System.Net; using System.Net.Http; using System.Security.Principal; using System.Text; using System.Threading; using System.Web.Http.Filters; namespace SCM.API { public class APIAuthorizeAttribute :AuthorizationFilterAttribute { public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext) { base.OnAuthorization(actionContext); if (Thread.CurrentPrincipal.Identity.IsAuthenticated) { return; } var authHeader = actionContext.Request.Headers.Authorization; if (authHeader != null) { if (authHeader.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) && !String.IsNullOrWhiteSpace(authHeader.Parameter)) { var credArrar = GetCredentials(authHeader); var userName = credArrar[0]; var key = credArrar[1]; string ip = System.Web.HttpContext.Current.Request.UserHostAddress; if (1 == 1) //!IsresourceOwner(userName, actionContext) { if (APIAuthorizeInfoValidate.ValidateApi(userName, key)) { var currentPrincipal = new GenericPrincipal(new GenericIdentity(userName), null); Thread.CurrentPrincipal = currentPrincipal; return; } } } } HandleUnauthorizeRequest(actionContext); } private string[] GetCredentials(System.Net.Http.Headers.AuthenticationHeaderValue authHeader) { //Base 64 encoded string var rawCred = authHeader.Parameter; var encoding = Encoding.GetEncoding("iso-8859-1"); var cred = encoding.GetString(Convert.FromBase64String(rawCred)); var credArray = cred.Split(':'); return credArray; } private bool IsresourceOwner(string username, System.Web.Http.Controllers.HttpActionContext actionContext) { var routeData = actionContext.Request.GetRouteData(); var resourceUsername = routeData.Values["username"] as string; if (resourceUsername == username) { return true; } return false; } private void HandleUnauthorizeRequest(System.Web.Http.Controllers.HttpActionContext ActionContext) { ActionContext.Response = ActionContext.Request.CreateResponse(HttpStatusCode.Unauthorized); ActionContext.Response.Headers.Add("WWW-Authenticate", "Basic Scheme='eLearning' location='http://192.168.60.31:81/help'"); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using System.Web; using Newtonsoft.Json; using SCM.API.Common; using System.Data.OracleClient; namespace SCM.API { public class APIAuthorizeInfo { public string api_usr_user { get; set; } public string api_key { get; set; } } public class APIAuthorizeInfoValidate { [DllImport("Iphlpapi.dll")] static extern int SendARP(Int32 DestIP, Int32 SrcIP, ref Int64 MacAddr, ref Int32 PhyAddrLen); [DllImport("Ws2_32.dll")] static extern Int32 inet_addr(string ipaddr); /// <summary> /// 身份验证:用户、口令、IP、MAC /// </summary> /// <param name="username">用户名</param> /// <param name="key">口令</param> /// <param name="ip">IP</param> /// <param name="mac">MAC</param> /// <returns></returns> public static bool ValidateApi(string username, string key) { string ip = APIAuthorizeInfoValidate.GetWebClientIp(); //获取用户IP string mac = APIAuthorizeInfoValidate.GetMacAddress(ip); //获取用户MAC地址 WebConfigHelper con = new WebConfigHelper(); var _APIAuthorizeInfo = JsonConvert.DeserializeObject<List<APIAuthorizeInfo>>(WebConfigHelper.ApiAuthorize); var ips = WebConfigHelper.IPs.Contains(",") ? WebConfigHelper.IPs.Split(',') : new string[] { WebConfigHelper.IPs }; var macs = WebConfigHelper.Macs.Contains(",") ? WebConfigHelper.Macs.Split(',') : new string[] { WebConfigHelper.Macs }; if (_APIAuthorizeInfo != null && _APIAuthorizeInfo.Count > 0) { foreach (var v in _APIAuthorizeInfo) { // if ( v.api_usr_user == username && v.api_key == key && ips.Contains(ip) && macs.Contains(mac) ) if (v.api_usr_user == username && v.api_key == key ) { string sql = @"update api_mstr set api_rmks = :api_rmks where API_USR_USER = :API_USR_USER"; OracleParameter[] pars = { new OracleParameter("api_rmks",OracleType.VarChar), new OracleParameter("API_USR_USER",OracleType.VarChar) }; pars[0].Value = ip; pars[1].Value = v.api_usr_user; int i = OracleHelper.ExecuteSql(sql,pars); return true; } } } return false; } /// <summary> /// 身份验证:用户、口令、IP /// </summary> /// <param name="username"></param> /// <param name="key"></param> /// <param name="ip"></param> /// <returns></returns> public static bool ValidateApi(string username, string key, string ip) { ip = GetWebClientIp(); //获取用户内部IP WebConfigHelper con = new WebConfigHelper(); var _APIAuthorizeInfo = JsonConvert.DeserializeObject<List<APIAuthorizeInfo>>(WebConfigHelper.ApiAuthorize); var ips = WebConfigHelper.IPs.Contains(",") ? WebConfigHelper.IPs.Split(',') : new string[] { WebConfigHelper.IPs }; if (_APIAuthorizeInfo != null && _APIAuthorizeInfo.Count > 0) { foreach (var v in _APIAuthorizeInfo) { if (v.api_usr_user == username && v.api_key == key && ips.Contains(ip)) { return true; } } } return false; } ///<summary> /// SendArp获取MAC地址 ///</summary> ///<param name="RemoteIP">目标机器的IP地址如(192.168.1.1)</param> ///<returns>目标机器的mac 地址</returns> public static string GetMacAddress(string RemoteIP) { StringBuilder macAddress = new StringBuilder(); try { Int32 remote = inet_addr(RemoteIP); Int64 macInfo = new Int64(); Int32 length = 6; SendARP(remote, 0, ref macInfo, ref length); string temp = Convert.ToString(macInfo, 16).PadLeft(12, '0').ToUpper(); int x = 12; for (int i = 0; i < 6; i++) { if (i == 5) { macAddress.Append(temp.Substring(x - 2, 2)); } else { macAddress.Append(temp.Substring(x - 2, 2) + "-"); } x -= 2; } return macAddress.ToString(); } catch { return macAddress.ToString(); } } /// <summary> /// 获取用户IP /// </summary> /// <returns></returns> public static string GetWebClientIp() { string userIP = ""; try { if (System.Web.HttpContext.Current == null || System.Web.HttpContext.Current.Request == null || System.Web.HttpContext.Current.Request.ServerVariables == null) return ""; string CustomerIP = ""; //CDN加速后取到的IP CustomerIP = System.Web.HttpContext.Current.Request.Headers["Cdn-Src-Ip"]; if (!string.IsNullOrEmpty(CustomerIP)) { return CustomerIP; } CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (!String.IsNullOrEmpty(CustomerIP)) return CustomerIP; if (System.Web.HttpContext.Current.Request.ServerVariables["HTTP_VIA"] != null) { CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (CustomerIP == null) CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; } else { CustomerIP = System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; } if (string.Compare(CustomerIP, "unknown", true) == 0) return System.Web.HttpContext.Current.Request.UserHostAddress; return CustomerIP; } catch { } return userIP; } public static string GetWebClientIp1() { try { string result = String.Empty; result = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (result != null && result != String.Empty) { //可能有代理 if (result.IndexOf(".") == -1) //没有“.”肯定是非IPv4格式 result = null; else { if (result.IndexOf(",") != -1) { //有“,”,估计多个代理。取第一个不是内网的IP。 result = result.Replace(" ", "").Replace("'", ""); string[] temparyip = result.Split(",;".ToCharArray()); for (int i = 0; i < temparyip.Length; i++) { if (IsIPAddress(temparyip[i]) && temparyip[i].Substring(0, 3) != "10." && temparyip[i].Substring(0, 7) != "192.168" && temparyip[i].Substring(0, 7) != "172.16.") { return temparyip[i]; //找到不是内网的地址 } } } else if (IsIPAddress(result)) //代理即是IP格式 ,IsIPAddress判断是否是IP的方法, return result; else result = null; //代理中的内容 非IP,取IP } } string IpAddress = (HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null && HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != String.Empty) ? HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] : HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; if (null == result || result == String.Empty) result = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; if (result == null || result == String.Empty) result = HttpContext.Current.Request.UserHostAddress; return result; } catch { return null; } } #region bool IsIPAddress(str1) 判断是否是IP格式 /**/ /// <summary> /// 判断是否是IP地址格式 0.0.0.0 /// </summary> /// <param name="str1">待判断的IP地址</param> /// <returns>true or false</returns> public static bool IsIPAddress(string str1) { if (str1 == null || str1 == string.Empty || str1.Length < 7 || str1.Length > 15) return false; string regformat = @"^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$"; Regex regex = new Regex(regformat, RegexOptions.IgnoreCase); return regex.IsMatch(str1); } #endregion } }
using System.Data; using System.Data.OracleClient; namespace SCM.API.Common { public class WebConfigHelper { public static string ApiAuthorize { get; set; } public static string IPs { get; set; } public static string Macs { get; set; } public WebConfigHelper() { string sql = @"select * from api_mstr"; using (OracleConnection conn = new OracleConnection(GetConnString.ConnectionString)) { conn.Open(); OracleCommand cmd = new OracleCommand(sql, conn); OracleDataAdapter myda = new OracleDataAdapter(cmd); DataTable dt = new DataTable(); myda.Fill(dt); ApiAuthorize = "["; for (int i = 0; i <= dt.Rows.Count - 1; i++) { ApiAuthorize += "{api_usr_user :'" + dt.Rows[i]["api_usr_user"].ToString()+"',"; ApiAuthorize += "api_key :'" + dt.Rows[i]["api_key"].ToString() + "'},"; IPs += dt.Rows[i]["api_ip"].ToString() + ","; Macs += dt.Rows[i]["api_mac"].ToString() + ","; } IPs = IPs.Substring(0, IPs.Length - 1); Macs = Macs.Substring(0, Macs.Length - 1); ApiAuthorize = ApiAuthorize.Substring(0, ApiAuthorize.Length - 1); ApiAuthorize += "]"; myda.Dispose(); } } } }
配置全局变量
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; namespace SCM.API { // 注意: 有关启用 IIS6 或 IIS7 经典模式的说明, // 请访问 http://go.microsoft.com/?LinkId=9394801 public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); HandlerConfig.RegisterHandlers(GlobalConfiguration.Configuration.MessageHandlers); // 使api返回为json GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear(); GlobalConfiguration.Configuration.Filters.Add(new APIAuthorizeAttribute()); } } }
配置WebApiConfig
using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; namespace SCM.API { public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); //配置返回的时间类型数据格式 ReturnJsonSerialiZerSettings(); config.Filters.Add(new APIAuthorizeAttribute()); } /// <summary> /// 返回Json序列化设置 /// </summary> private static void ReturnJsonSerialiZerSettings() { var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter; json.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Local; json.SerializerSettings.DateFormatString = "yyyy'-'MM'-'dd' 'HH':'mm':'ss"; json.SerializerSettings.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat; } } }
3、测试
与你共亲到无可亲密时,便知友谊万岁是尽头。