WebApi中的Basic认证

一.步骤

1.通过用户登录获取票据信息Ticket
2.访问WebApi时带上Ticket进行票据信息验证

二.验证过程及代码

1.通过用户登录获取票据信息

根据用户名和密码等一些其它的信息取得生成票据信息,得到Ticket
前端登录部分代码:

var ticket = "";

//登录一次获取Ticket
$("#btnLogin").on("click", function () {
    $.ajax({
        url: "/userapi/users/Login", type: "GET", data: { "Name": $("#txtName").val(), "Password": $("#txtPassword").val() }, success: function (data) {
            var result = JSON.parse(data);
            if (result.Result) {
                ticket = result.Ticket;//得到Ticket的值
            }
            else {
                alert("failed");
            }
        }, datatype: "json"
    });
});

WebApi后端部分登录获取票据信息代码:

[AllowAnonymous]//不需要验证票据信息,相当于通行证
[HttpGet]
public string Login(string name, string password)
{
    if (name.Equals("Admin") && password.Equals("123456"))
    {
        FormsAuthenticationTicket ticketObject = new FormsAuthenticationTicket(0, name, DateTime.Now,
                    DateTime.Now.AddHours(1), true, string.Format("{0}&{1}", name, password),
                    FormsAuthentication.FormsCookiePath);//根据用户信息得到一个Ticket
        var result = new { Result = true, Ticket = FormsAuthentication.Encrypt(ticketObject) };//对生成的Ticket进行加密
        return JsonConvert.SerializeObject(result);
    }
    else
    {
        var result = new { Result = false };
        return JsonConvert.SerializeObject(result);
    }
}

2.访问WebApi时带上Ticket进行票据信息验证

访问api前端部分代码:

$("#btnGet").on("click", function () {
    $.ajax({
        url: "/userapi/users/GetUserByName", type: "get", data: { "username": "Superman" },
        beforeSend: function (XHR) { //XHR:XML Http Request  
            //发送ajax请求之前向http的head头里面带上Ticket信息
            XHR.setRequestHeader('Authorization', 'BasicAuth ' + ticket);//这里有个坑:Authorization中有两个属性:1.Parameter参数  2.Scheme组合名称  要这两个都不为空,则Scheme名称+空格+Parameter参数才行,不加空格则默认为Scheme组合名称,parameter则为null
        },
        success: function (data) {
            alert(data);
        }, datatype: "json"
    });
});

在这里我们需要对自带的AuthorizeAttribute特性进行扩展,根据自己的WebApi项目设计在合适的位置添加一个BasicAuthorizeAttribute类(名称随意,规范就行),需要继承AuthorizeAttribute,下面用代码展示:

public class BasicAuthorizeAttribute : AuthorizeAttribute//继承自带的特性验证
{
    /// <summary>
    /// 访问api前进来完成验证
    /// </summary>
    /// <param name="actionContext"></param>
    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        var authorization = actionContext.Request.Headers.Authorization;//获取在head中设置的Authorization信息

        //检查方法和控制器上是否有AllowAnonymousAttribute这个特性,有的话直接可以访问,不需要验证
        if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(true).Count != 0
            || actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(true).Count != 0)
        {
            base.OnAuthorization(actionContext);//有AllowAnonymousAttribute特性才能正确的访问方法
        }
        else if (authorization != null && authorization.Parameter != null)
        {
            //用户验证逻辑
            if (ValidateTicket(authorization.Parameter))
            {
                base.IsAuthorized(actionContext);//正确的访问方法
            }
            else
            {
                this.HandleUnauthorizedRequest(actionContext);//没有权限,返回一个Unauthorized状态码,没有授权
            }
        }
        else
        {
            this.HandleUnauthorizedRequest(actionContext);//没有权限
        }
    }
    /// <summary>
    /// 没有访问权限的信息返回
    /// </summary>
    /// <param name="actionContext"></param>
    protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        var challengeMessage = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);//告诉浏览器需要授权验证:401 Unauthorized
        //challengeMessage.Headers.Add("WWW-Authenticate", "Basic");//权限信息放在basic

        base.HandleUnauthorizedRequest(actionContext);//返回没有授权的信息
    }
    /// <summary>
    /// 权限验证
    /// </summary>
    /// <param name="encryptTicket">加密后的Ticket信息</param>
    /// <returns></returns>
    private bool ValidateTicket(string encryptTicket)
    {
        var strTicket = FormsAuthentication.Decrypt(encryptTicket).UserData;//解密Ticket
        return string.Equals(strTicket, string.Format("{0}&{1}", "Admin", "123456"));
        //应该分拆后去数据库验证
        //过期还没有验证
    }
}

接下来我们把需要验证的控制器或者方法上加上BasicAuthorizeAttribute特性即可验证,在需要放行的方法加上AllowAnonymousAttribute即可不验证

posted @ 2020-04-12 17:59  WEasiness  阅读(266)  评论(0)    收藏  举报