• Web API(七):Basic基础认证


    1、WebApi中为什么需要身份认证

    我们在使用WebApi的时候,都是通过URL去获取数据。也就是说,任何人只要知道了URL地址,就能随意的访问后台的服务接口,就可以访问或者修改数据库数据了,这样就会导致很严重的后果。

    1、我们不加身份认证,匿名用户可以直接通过url随意访问接口:

    2、增加了身份认证之后,只有带了票据的请求才能访问对应的接口。

    2、常见的认证方式

    WebApi中常见的认证方式有如下几种:

    • FORM身份验证
    • 集成WINDOWS验证
    • Basic基础认证
    • Digest摘要认证

    3、Basic基础认证

    1、Basic基础认证原理

    Basic认证的基本原理就是加密用户信息生成Ticket,每次请求后端API接口的时候把生成的Ticket信息加到http请求的头部传给后端进行验证。具体步骤如下:

    1、登录的时候验证用户名和密码,如果验证通过,则将用户名和密码按照一定的规则生成加密后的票据信息Ticket,然后将Ticket传递到前端。

    2、如果登录成功,前端定义一个全局的变量接收API接口返回的Ticket信息。

    3、前端界面再次发起ajax请求后端API接口的时候,将Ticket信息加入到HTTP请求的Head里面,将Ticket信息随着http请求一起发送到后端API接口。

    4、在后端的WebApi服务中定义一个类,该类继承自AuthorizeAttribute类,然后重新父类里面的OnAuthorization方法,在OnAuthorization方法里面,通过actionContext参数取得http请求的Head,从Head里面可以获取前端传递过来的Ticket信息。将Ticket解密得到用户名和密码,然后验证用户名和密码是否正确。如果正确,表示验证通过。如果不正确,则返回401未授权的错误。

    4、Basic基础认证示例代码

    假设我们要访问Users控制器的Get接口,该接口方法返回int类型的List集合。

    1、登录的API接口

    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Web.Http;
    using System.Web.Security;
    using WebApiBasicAuthorize.CustomerAttribute;
    using WebApiBasicAuthorize.Entity;
    
    namespace WebApiBasicAuthorize.Controllers
    {
        [BasicAuthorize]
        public class UsersController : ApiController
        {
            /// <summary>
            /// 允许匿名登录
            /// </summary>
            /// <param name="account"></param>
            /// <param name="password"></param>
            /// <returns></returns>
            [AllowAnonymous]
            [HttpGet]
            public IHttpActionResult Login(string account,string password)
            {
                ReturnValueEntity entity = new ReturnValueEntity();
                // 真实生产环境中要去数据库校验account和password
                if (account.ToUpper().Trim().Equals("ADMIN") && password.Trim().Equals("123456"))
                {
                    FormsAuthenticationTicket ticket = 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(ticket) };
                    entity.Result = true;
                    entity.Ticket = FormsAuthentication.Encrypt(ticket);
                }
                else
                {
                    entity.Result = false;
                    entity.Ticket = "";
                }
                return Json<ReturnValueEntity>(entity);
            }
    
            [HttpGet]
            public IHttpActionResult Get()
            {
                List<int> list = new List<int>();
                list.Add(1);
                list.Add(2);
                list.Add(3);
                list.Add(4);
                list.Add(5);
                return Json<List<int>>(list);
            }
        }
    }

    在Login方法上面添加 [AllowAnonymous]特性,表示允许匿名登录。

    2、基础认证接口

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Http;
    using System.Web.Http.Controllers;
    using System.Web.Security;
    
    namespace WebApiBasicAuthorize.CustomerAttribute
    {
        /// <summary>
        ///  自定义特性继承自AuthorizeAttribute
        /// </summary>
        public class BasicAuthorizeAttribute:AuthorizeAttribute
        {
            public override void OnAuthorization(HttpActionContext actionContext)
            {
                // 从当前http请求Request对象的头部信息里面获取Authorization属性
                var authorization = actionContext.Request.Headers.Authorization;
                // 判断控制器获取action方法上面是否有AllowAnonymousAttribute特性,如果有,则允许匿名登录
                if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(true).Count != 0
                    || actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(true).Count != 0)
                {
                    base.OnAuthorization(actionContext);
                }
                else if (authorization != null && authorization.Parameter != null)
                {
                    // 验证用户逻辑
                    if (ValidateTicket(authorization.Parameter))
                    {
                        // 验证通过
                        base.IsAuthorized(actionContext);
                    }
                    else
                    {
                        this.HandleUnauthorizedRequest(actionContext);
                    }
                }
                else
                {
                    // 返回401没有授权的状态码
                    this.HandleUnauthorizedRequest(actionContext);
                }
    
            }
    
            /// <summary>
            /// 验证Ticket信息
            /// </summary>
            /// <param name="encryptTicket"></param>
            /// <returns></returns>
            private bool ValidateTicket(string encryptTicket)
            {
                // 解密Ticket
                var strTicket = FormsAuthentication.Decrypt(encryptTicket).UserData;
                // 从Ticket里面获取用户名和密码
                int index = strTicket.IndexOf("&");
                //string strUser=strTicket
                string[] array = strTicket.Split('&');
                string strUser = array[0];
                string strPwd = array[1];
                // 真实生产环境中应该用解密的用户名和密码去数据库验证,这里为了演示方便
                // 假定用户名是Admin,密码是123456
                if(strUser.Equals("Admin")&&strPwd.Equals("123456"))
                {
                    return true;
                }
                else
                {
                    return false;
                }           
            }
        }
    }

    3、前端代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>权限认证</title>
        <script src="jquery-1.10.2.min.js"></script>
        <script>
            // 定义全局的ticket变量,用来保存登录成功以后的Ticket值
            var ticket;
           window.onload=function(){
               
           };
    
           function Login(){
               $.ajax({
                   url:"http://localhost:20033/api/users?account="+$("#acc").val().trim()+"&password="+$("#pwd").val().trim(),
                   type:"Get",
                   dataType:"json",
                   "headers": {
                    "Content-Type": "application/json",
                    "cache-control": "no-cache"
                  },
                   success:function(data){
                       if(result.Result){
                           ticket=data.Ticket;
                       }else{
                           alert("失败");
                       }
                   },
                   error:function(data){
                       alert(data);
                   }
               });
           };
    
           function Test(){
               alert(ticket);
               $.ajax({
                   url:'http://localhost:20033/api/users',
                   type:"Get",
                   dataType:"json",
                   beforeSend:function(XHR){
                       //发送ajax请求之前向http的head里面加入验证信息
                       XHR.setRequestHeader('Authorization','BasicAuth '+ticket);
                   },
                   success:function(data){
                       alert(data);
                   },
                   error:function(data){
                       alert(data);
                   }
    
               });
    
           };
        </script>
    </head>
    
    <body>
        <div>
            <div>
                    <label>用户名:</label>
                    <input type="text" id="acc">
            </div>
            <div>
                    <label>密码:</label>
                    <input type="password" id="pwd">
            </div>
            <div>
                    <input type="button" id="btnLogin" onclick="Login()" value="登录">
            </div>
            <div>
                <input type="button" id="GetAccount" onclick="Test()" value="测试">
            </div>
        </div>
    </body>
    </html>
    

    这里需要说明的是,我们在发送ajax请求之前,通过 XHR.setRequestHeader('Authorization', 'BasicAuth ' + Ticket); 这句向http请求的Head里面添加Ticket信息。

    通过上面的几步就可以达到Basic认证的效果了。

    注意:后端的WebApi接口要配置允许跨域访问。

    4、优化

    每增加一个控制器,都需要在相应的控制器上面加[BasicAuthorize]特性,可以定义一个公共的控制器父类,该父类继承自ApiController,然后其他控制器继承该父类。

  • 相关阅读:
    多任务并行
    不同方法来移动数据库(更改磁盘时用)(转)
    ASP.NET执行SQL超时的解决方案
    SQL Server 简单模式下,误删除堆表记录如何恢复(绕过页眉校验) (转)
    关于跟踪标记
    .NET分布式事务处理
    安装SQL Server 2005时出现COM+的警告/错误,下面是微软给出的解决方法。
    PHP中如何获取多个checkbox的值
    C# 模拟post数据提交时 出现如下错误: System.Net.WebException: 远程服务器返回错误: (417) Expectation Failed 的解决办法
    winform出现"LC.exe"已退出,代码为1
  • 原文地址:https://www.cnblogs.com/dotnet261010/p/10059938.html
Copyright © 2020-2023  润新知