C#/.NET 分布式专题(SOA【面向服务】WebApi权限认证)

权限认证:是需要的,http地址,是公开的,所以需要权限认证
session–webapi默认是不支持session–RESTful—可以自行扩展去支持
无状态:第2次请求和第1次请求不关联
1 登陆过程,拿到令牌–token–ticket–许可证
2 验证成功–账号+密码+其他信息+时间–加密一下得到ticket—返回给客户端
3 请求时,ajax里面带上这个ticket(header)
4 接口调用时,就去验证ticket,解密一下,看看信息,看看时间
5 每个方法都需要验证下ticket,基于filter来实现

用户登入的后端api,返回token

#region 用户登陆
[CustomAllowAnonymousAttribute]
[HttpGet]
public string Login(string account, string password)
{
    if ("Admin".Equals(account) && "123456".Equals(password))//应该数据库校验
    {
        FormsAuthenticationTicket ticketObject = new FormsAuthenticationTicket(0, account, DateTime.Now, DateTime.Now.AddHours(1), true, string.Format("{0}&{1}", account, password), FormsAuthentication.FormsCookiePath);
        var result = new
        {
            Result = true,
            Ticket = FormsAuthentication.Encrypt(ticketObject)
        };
        return JsonConvert.SerializeObject(result);
    }
    else
    {
        var result = new { Result = false };
        return JsonConvert.SerializeObject(result);
    }
}
#endregion

用户登入的前端,获取token

$("#btnLogin").on("click", function () {
   $.ajax({
       url: "/api/users/Login",
       type: "GET",
       data: { "Account": $("#txtAccount").val(), "Password": $("#txtPassword").val() },
       success: function (data) {
           var result = JSON.parse(data);
           if (result.Result) {
               ticket = result.Ticket;
               alert(result.Ticket);
           }
           else {
               alert("failed");
           }
       }, datatype: "json"
   });
});

var ticket = "";//登陆后放在某个html里面,ajax都得带上

用户请求,带上前面获取token

前端版

$("#btnGet1").on("click", function () {
    //$.ajax({ url: "/api/users", type: "get", data: { "userName": "Superman" }, success: function (data) { alert(data); }, datatype: "json" });//指向接口,参数匹配的,大小写不区分
    $.ajax({
        //url: "/api/users/GetUserByName?ticket=" + ticket
        url: "/api/users/GetUserByName", type: "get", data: { "username": "Superman" },
        beforeSend: function (XHR) {
            //发送ajax请求之前向http的head里面加入验证信息
            XHR.setRequestHeader('Authorization', 'BasicAuth ' + ticket);
        },
        success: function (data) {
            alert(data);
        }, datatype: "json"
    });
});

后端版

#region 用户登陆 获取ticket后使用
private void AuthorizationDemo()
{
    string ticket = "";
    {
        string loginUrl = "http://localhost:8088/api/users/Login?Account=Admin&Password=123456";
        var handler = new HttpClientHandler();//{ AutomaticDecompression = DecompressionMethods.GZip };

        using (var http = new HttpClient(handler))
        {
            var response = http.GetAsync(loginUrl).Result;//拿到异步结果
            Console.WriteLine(response.StatusCode); //确保HTTP成功状态值
                                                    //await异步读取最后的JSON(注意此时gzip已经被自动解压缩了,因为上面的AutomaticDecompression = DecompressionMethods.GZip)
            ticket = response.Content.ReadAsStringAsync().Result.Replace("\"{\\\"Result\\\":true,\\\"Ticket\\\":\\\"", "").Replace("\\\"}\"", "");
            //ticket = JsonHelper.StringToObject<TicketModel>(response.Content.ReadAsStringAsync().Result).Ticket;
        }
    }
    {
        string url = "http://localhost:8088/api/users/GetUserByName?username=superman";
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        request.Timeout = 30 * 1000;
        request.Headers.Add(HttpRequestHeader.Authorization, "BasicAuth " + ticket);//头文件增加Authorization
        //request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36";
        //request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
        string result = "";
        using (var res = request.GetResponse() as HttpWebResponse)
        {
            if (res.StatusCode == HttpStatusCode.OK)
            {
                StreamReader reader = new StreamReader(res.GetResponseStream(), Encoding.UTF8);
                result = reader.ReadToEnd();
            }
        }
    }
    {
        string url = "http://localhost:8088/api/users/GetUserByName?username=superman";
        var handler = new HttpClientHandler();

        using (var http = new HttpClient(handler))
        {
            http.DefaultRequestHeaders.Add("Authorization", "BasicAuth " + ticket);//头文件增加Authorization
            var response = http.GetAsync(url).Result;
            Console.WriteLine(response.StatusCode);
            string result = response.Content.ReadAsStringAsync().Result;
        }
    }
}
#endregion

权限校验特性和跳过校验的两个特性

public class CustomBasicAuthorizeAttribute : AuthorizeAttribute
{
   /// <summary>
   /// action前会先来这里完成权限校验
   /// </summary>
   /// <param name="actionContext"></param>
   public override void OnAuthorization(HttpActionContext actionContext)
   {
       //actionContext.Request.Headers["Authorization"]
       if (actionContext.ActionDescriptor.GetCustomAttributes<CustomAllowAnonymousAttribute>().FirstOrDefault() != null)
       {
           return;//继续
       }
       else if (actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<CustomAllowAnonymousAttribute>().FirstOrDefault() != null)
       {
           return;//继续
       }
       else
       {
           var authorization = actionContext.Request.Headers.Authorization;
           if (authorization == null)
           {
               this.HandlerUnAuthorization();
           }
           else if (this.ValidateTicket(authorization.Parameter))
           {
               return;//继续
           }
           else
           {
               this.HandlerUnAuthorization();
           }
       }
   }

   private void HandlerUnAuthorization()
   {
       throw new HttpResponseException(System.Net.HttpStatusCode.Unauthorized);
   }
   private bool ValidateTicket(string encryptTicket)
   {
       ////解密Ticket
       //if (string.IsNullOrWhiteSpace(encryptTicket))
       //    return false;
       try
       {
           var strTicket = FormsAuthentication.Decrypt(encryptTicket).UserData;
           //FormsAuthentication.Decrypt(encryptTicket).
           return string.Equals(strTicket, string.Format("{0}&{1}", "Admin", "123456"));//应该分拆后去数据库验证
       }
       catch (Exception ex)
       {
           return false;
       }

   }
}
public class CustomAllowAnonymousAttribute : Attribute
{
}

对于权限的控制器和方法注册就不说了,全局注册说下

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API 配置和服务
        config.DependencyResolver = new UnityDependencyResolver(ContainerFactory.BuildContainer());

        //config.Filters.Add(new CustomBasicAuthorizeAttribute());//全局注册
        config.Filters.Add(new CustomExceptionFilterAttribute());

        config.Services.Replace(typeof(IExceptionHandler), new CustomExceptionHandler());//替换全局异常处理类

        //config.EnableCors(new EnableCorsAttribute("*", "*", "*"));//全部都允许,

        // Web API 路由
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
         name: "CustomApi",//默认的api路由
         routeTemplate: "api/{controller}/{action}/{id}",//正则规则,以api开头,第二个是控制器  第三个是参数
         defaults: new { id = RouteParameter.Optional }
     );


        config.Routes.MapHttpRoute(
            name: "DefaultApi",//默认的api路由
            routeTemplate: "api/{controller}/{id}",//正则规则,以api开头,第二个是控制器  第三个是参数
            defaults: new { id = RouteParameter.Optional }
        );


    }
}
发布了143 篇原创文章 · 获赞 117 · 访问量 4240

猜你喜欢

转载自blog.csdn.net/weixin_41181778/article/details/103856458