C\#진급 시리즈 WebApi 인증 솔 루 션 추천:Basic 기초 인증

15333 단어 WebApi인증C#
선언:최근 에 데이터베이스 안전 에 대한 문제 가 토론 되 었 기 때문에 WebApi 서비스 가 아무런 검증 도 하지 않 은 문 제 를 초래 했다.즉,누구나 인터페이스의 url 을 알 면 http 요청 을 모 의 하여 우리 의 서비스 인 터 페 이 스 를 방문 하여 데이터 베 이 스 를 삭제 하고 검사 할 수 있 습 니 다.그 결 과 는 생각 만 해도 무 섭 습 니 다.한바탕 고생 끝 에 인터페이스의 신분 인증 을 더 한 셈 이다.이 기록 에서 신분 인증 이 필요 한 원우 들 에 게 도 참 고 를 제공한다.
1.왜 신분 인증 이 필요 합 니까?
앞에서 말 했 듯 이 인증 을 사용 하지 않 으 면 익명 의 사용자 가 Google 서비스의 url 을 알 면 Google 서비스 인 터 페 이 스 를 임의로 방문 하여 데이터 베 이 스 를 방문 하거나 수정 할 수 있 습 니 다.
1.저 희 는 인증 을 하지 않 고 익명 의 사용 자 는 url 을 통 해 인 터 페 이 스 를 임의로 방문 할 수 있 습 니 다.

 

익명 의 사용자 가 url 을 통 해 우리 의 데이터 인 터 페 이 스 를 직접 방문 할 수 있 고 최종 적 으로 무슨 일이 발생 할 지 마음대로 생각 할 수 있 습 니 다.
2.신분 인증 을 추가 한 후에 저희 가 어음 을 방문 하 라 는 요청 을 가 져 와 야 저희 인 터 페 이 스 를 방문 할 수 있 습 니 다.
예 를 들 어 우 리 는 url 을 통 해 직접 방문 하면 401 로 돌아 갑 니 다.
 
 정상 적 인 절차 의 요청 이 라면 어음 을 가 져 오 면 OK 입 니 다.

정상 적 인 절차 의 요청 은 요청 메시지 의 머리 에 Authorization 을 추가 합 니 다.그 값 은 바로 우리 의 Ticket 어음 정보 입 니 다.
2.Basic 기초 인증 의 원리 분석
1.흔히 볼 수 있 는 인증 방식
우 리 는 asp.net 의 인증 메커니즘 이 여러 가지 가 있다 는 것 을 안다.WebApi 에 대해 서도 예외 가 아니다.흔히 볼 수 있 는 인증 방식 은
  • FORM 인증
  • 통합 WINDOWS 검증
  • Basic 기초 인증
  • Digest 요약 인증
  • 정원 에는 WebApi 인증 에 관 한 글 이 많 고 각종 인증 방식 이 언급 되 지만 감각 이 섬세 하지 않다.여기 서도 어떤 검증 방식 이 어떤 사용 장면 에 적용 되 는 지 연구 하고 싶 지 않다.블 로 거들 은'욕심 이 많 으 면 잘 씹 을 수 없다'고 생각 하기 때문에 블 로 거들 의 능력 에 한계 가 있 을 수도 있다.인증 체제 에 대해 그 중의 하 나 를 이해 하면 다른 것 은 모두 융합 되 어 관통 할 수 있다.이 편 은 Basic 기초 인증 을 사용 하여 전체 과정 을 상세 하 게 설명 한다.
    2.Basic 기초 인증 원리
     우 리 는 인증 의 목적 이 안전 에 있다 는 것 을 알 고 있 습 니 다.그러면 어떻게 안전 을 보장 할 수 있 습 니까?자주 사용 하 는 수단 은 당연히 암호 화 이다.Basic 인증 도 예외 가 아니다.주요 원 리 는 사용자 정 보 를 암호 화하 고 어음 을 생 성하 여 요청 할 때마다 어음 을 가 져 와 검증 하 는 것 이다.이렇게 말 하면 약간 추상 적일 수 있 습 니 다.우 리 는 모든 절 차 를 상세 하 게 분해 합 니 다.
  • 먼저 로그 인 할 때 사용자 명,비밀 번 호 를 검증 하고 로그 인 에 성공 하면 사용자 명,비밀 번 호 를 일정한 규칙 에 따라 암호 화 된 어음 정보 Ticket 을 생 성하 여 어음 정 보 를 전단 으로 되 돌려 줍 니 다.
  • 로그 인 에 성공 하면 전단 에 어음 정 보 를 받 은 다음 에 메 인 화면 으로 이동 하고 어음 정 보 를 메 인 인터페이스의 Action Result 에 가 져 옵 니 다.(예 를 들 어 점프 하 는 url 은 이렇게 쓸 수 있 습 니 다./Home/Index?Ticket=Ticket)
  • 메 인 인터페이스의 Action Result 에서 매개 변 수 를 통 해 어음 정보 Ticket 을 얻 은 다음 에 Ticket 정 보 를 ViewBag 에 저장 하여 전단 으로 전달 합 니 다.
  • 메 인 인터페이스의 전단 에 Ajax 요청 을 보 낼 때 어음 정 보 를 요청 한 Head 에 넣 고 어음 정 보 를 요청 에 따라 서버 로 보 냅 니 다.
  • 은 웹 Api 서비스 에서 Authorize Attribute 클래스 를 계승 한 다음 에 부모 클래스 의 OnAuthorization 방법 을 다시 쓰 고 OnAuthorization 방법 에서 현재 http 에서 요청 한 Head 를 가 져 와 Head 에서 우리 전단 에서 보 내 온 어음 정 보 를 가 져 옵 니 다.어음 정 보 를 복호화 하고 복호화 한 정보 에서 사용자 이름과 비밀 번 호 를 얻 은 다음 에 사용자 이름과 비밀번호 가 정확 한 지 검증 합 니 다.정확 하 다 면 검증 이 통과 되 었 음 을 표시 합 니 다.그렇지 않 으 면 검증 되 지 않 은 요청 401 을 되 돌려 줍 니 다.
  •  이 기본 적 인 원리 는다음은 이 원리 에 따라 모든 코드 가 어떻게 실현 되 는 지 살 펴 보 자.
    3.Basic 기초 인증 코드 예제
    먼저 우리 의 예시 장면 을 말씀 드 리 겠 습 니 다.지난번 에  CORS  을 소 개 했 을 때 우 리 는 하나의 해결 방안 에 두 개의 프로젝트 웹 과 WebApiCORS 를 넣 었 습 니 다.우 리 는 이번에 도 이 를 예 로 들 어 설명 합 니 다.
    1.로그 인 과정 1.1,웹 전단
    
    <body>
     <div style="text-align:center;"> 
      <div>   :<input type="text" id="txt_username" /></div>
      <div>   :<input type="password" id="txt_password" /></div>
      <div><input type="button" value="  " id="btn_login" class="btn-default" /></div>
     </div>
    </body>
    
    $(function () {
     $("#btn_login").click(function () {
      $.ajax({
       type: "get",
       url: "http://localhost:27221/api/User/Login",
       data: { strUser: $("#txt_username").val(), strPwd: $("#txt_password").val() },
       success: function (data, status) {
        if (status == "success") {
         if (!data.bRes){
          alert("    ");
          return;
         }
         alert("    ");
                //                    
         window.location = "/Home/Index?UserName=" + data.UserName + "&Ticket=" + data.Ticket;
        }
       },
       error: function (e) {
       },
       complete: function () {
    
       }
    
      });
     });
    });
    1.2 로그 인 API 인터페이스
    
      public class UserController : ApiController
     {
      /// <summary>
      ///     
      /// </summary>
      /// <param name="strUser"></param>
      /// <param name="strPwd"></param>
      /// <returns></returns>
      [HttpGet]
      public object Login(string strUser, string strPwd)
      {
       if (!ValidateUser(strUser, strPwd))
       {
        return new { bRes = false };
       }
       FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(0, strUser, DateTime.Now,
           DateTime.Now.AddHours(1), true, string.Format("{0}&{1}", strUser, strPwd),
           FormsAuthentication.FormsCookiePath);
       //      、    、        
       var oUser = new UserInfo { bRes = true, UserName = strUser, Password = strPwd, Ticket = FormsAuthentication.Encrypt(ticket) };
       //        session ,             
       HttpContext.Current.Session[strUser] = oUser;
       return oUser;
      }
    
      //       (             )
      private bool ValidateUser(string strUser, string strPwd)
      {
       if (strUser == "admin" && strPwd == "123456")
       {
        return true;
       }
       else
       {
        return false;
       }
      }
     }
    
     public class UserInfo
     {
      public bool bRes { get; set; }
    
      public string UserName { get; set; }
    
      public string Password { get; set; }
    
      public string Ticket { get; set; }
     }
    여기 서 주의해 야 할 것 은 WebApi 가 기본적으로 Session 을 열지 않 았 기 때문에 설정 을 하고 수 동 으로 session 을 사용 해 야 한 다 는 것 입 니 다.참고:https://www.jb51.net/article/143197.htm
    위의 원리 부분 에서 말 한 바 와 같이 로그 인 에 실패 하면 바로 돌아 갑 니 다.성공 하면 생 성 된 어음 Ticket 을 전단 으로 가 져 와 메 인 인터페이스/Home/Index 로 전달 합 니 다.다음은 메 인 인터페이스 Home/Index 를 살 펴 보 겠 습 니 다.
    2./Home/Index 메 인 인터페이스
    
      public class HomeController : Controller
     {
      // GET: Home
      public ActionResult Index(string UserName, string Ticket)
      {
       ViewBag.UserName = UserName;
       ViewBag.Ticket = Ticket;
       return View();
      }
     }
    
    <html>
    <head>
     <meta name="viewport" content="width=device-width" />
     <title>Index</title>
     <script src="~/Content/jquery-1.9.1.js"></script>
     <link href="~/Content/bootstrap/css/bootstrap.css" rel="stylesheet" />
     <script src="~/Content/bootstrap/js/bootstrap.js"></script>
     <script src="~/Scripts/Home/Index.js"></script>
     <script type="text/javascript">
      //             
      var UserName = '@ViewBag.UserName';
      var Ticket = '@ViewBag.Ticket';
     </script>
    </head>
    <body>
     <div>      :'@ViewBag.UserName'</div>
    
     <div id="div_test">
    
     </div>
    </body>
    </html>
    
    $(function () {
     $.ajax({
      type: "get",
      url: "http://localhost:27221/api/Charging/GetAllChargingData",
      data: {},
      beforeSend: function (XHR) {
       //  ajax     http head        
       XHR.setRequestHeader('Authorization', 'BasicAuth ' + Ticket);
      },
      success: function (data, status) {
       if (status == "success") {
        $("#div_test").html(data);
       }
      },
      error: function (e) {
       $("#div_test").html("Error");
      },
      complete: function () {
    
      }
    
     });
    });
    여기 서 설명 해 야 할 것 은 ajax 요청 을 보 내기 전에 통과 하 는 것 입 니 다. XHR.setRequestHeader('Authorization', 'BasicAuth ' + Ticket); 이 한 마디 는 요청 한 메시지 머리 에 어음 정 보 를 추가 했다.바로 여기에 이 문장 을 넣 었 기 때문에 우리 다음 그림 의 빨 간 선 부분 이 있 습 니 다.

    3.WebApiCORS 인증 부분(중점)
    위/Home/Index 페이지 에서 ajax 요청 서 비 스 를 보 낸 것 을 보 았 습 니 다. http://localhost:27221/api/Charging/GetAllChargingData 이 인터페이스,그러면 우 리 는 WebApi 에서 이 요청 과 합 법 적 인 요청 을 어떻게 검증 합 니까?다음은 검증 의 이 과정 을 중점적으로 살 펴 보 자.
    3.1.WebApiCORS 프로젝트 에서 RequestAuthorizeAttribute 클래스 를 사용자 정의 하여 AuthorizeAttribute 클래스 를 계승 합 니 다.그리고 OnAuthorization 방법 을 다시 쓰 고 이 방법 에서 요청 헤더 의 Ticket 정 보 를 찾 은 다음 사용자 이름 비밀번호 가 합 리 적 인지 확인 합 니 다.
    
       /// <summary>
     ///                
     /// </summary>
     public class RequestAuthorizeAttribute : AuthorizeAttribute
     {
      //         ,        Ticket  
      public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
      {
       // http              ,           ticket
       var authorization = actionContext.Request.Headers.Authorization;
       if ((authorization != null) && (authorization.Parameter != null))
       {
        //    ticket,            
        var encryptTicket = authorization.Parameter;
        if (ValidateTicket(encryptTicket))
        {
         base.IsAuthorized(actionContext);
        }
        else
        {
         HandleUnauthorizedRequest(actionContext);
        }
       }
       //           ,         ,      401
       else
       {
        var attributes = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>();
        bool isAnonymous = attributes.Any(a => a is AllowAnonymousAttribute);
        if (isAnonymous) base.OnAuthorization(actionContext);
        else HandleUnauthorizedRequest(actionContext);
       }
      }
    
      //       (             )
      private bool ValidateTicket(string encryptTicket)
      {
       //  Ticket
       var strTicket = FormsAuthentication.Decrypt(encryptTicket).UserData;
    
       // Ticket          
       var index = strTicket.IndexOf("&");
       string strUser = strTicket.Substring(0, index);
       string strPwd = strTicket.Substring(index + 1);
    
       if (strUser == "admin" && strPwd == "123456")
       {
        return true;
       }
       else
       {
        return false;
       }
      }
     }
    3.2 구체 적 인 Api 인터페이스 에 사용자 정의 클래스 의 특성 추가
    
    [RequestAuthorize]
     public class ChargingController : ApiController
     {
      /// <summary>
      ///       
      /// </summary>
      /// <returns>    </returns>
      [HttpGet]
      public string GetAllChargingData()
      {
       return "Success";
      }
    
      /// <summary>
      ///     Id     
      /// </summary>
      /// <param name="id">  Id</param>
      /// <returns>    </returns>
      [HttpGet]
      public string GetAllChargingData(string id)
      {
       return "ChargingData" + id;
      }
    
     }
    특성 레이 블 이 추 가 된 후 이 API 의 인 터 페 이 스 를 요청 할 때마다 프로그램 은 우리 오 버 라 이 드 의 OnAuthorization()방법 에 먼저 들 어가 검증 이 통 과 된 후에 야 해당 하 는 방법 으로 실행 되 며 그렇지 않 으 면 401 로 돌아 갑 니 다.
    최적화
     위의 몇 단 계 를 통 해 우리 가 원 하 는 신분 인증 효 과 를 얻 을 수 있 지만 항상 불편 하고 주로 불편 한 점 은 다음 과 같다.
    1.API 를 새로 만 들 때마다 대응 하 는 인터페이스 에[RequestAuthorize]라 는 것 을 표시 해 야 하기 때문에 매우 번거롭다.
    2.ajax 요청 을 보 낼 때마다 beforeSend 이벤트 에 XHR.setRequestHeader('Authorization','Basic Auth'+Ticket)를 추가 합 니 다.이것 도 귀 찮 은 것 같 아 요.
    상기 두 가지 에 대하 여 우 리 는 최적화 하 였 다.
    1.API 문제 해결
    API 에 공통 부모 클래스 를 추가 하고 부모 클래스 에[RequestAuthorize]를 표시 하면 됩 니 다.
    
    namespace WebApiCORS.Controllers
    {
     [RequestAuthorize]
     [EnableCors(origins: "*", headers: "*", methods: "*")]
     public class BaseApiController : ApiController
     {
     }
    }
    
    namespace WebApiCORS.Controllers
    {
     public class ChargingController : BaseApiController
     {
      /// <summary>
      ///       
      /// </summary>
      /// <returns>    </returns>
      [HttpGet]
      public string GetAllChargingData()
      {
       return "Success";
      }
    
      /// <summary>
      ///     Id     
      /// </summary>
      /// <param name="id">  Id</param>
      /// <returns>    </returns>
      [HttpGet]
      public string GetAllChargingData(string id)
      {
       return "ChargingData" + id;
      }
      }
    }
     메모:로그 인 요청 은 검증 할 필요 가 없습니다.로그 인 할 때 어음 이 발생 하지 않 았 기 때문에 로그 인 한 API 는 BaseApicontroller 를 계승 할 수 없습니다.
    2.ajax 문제 해결
    우리 가 JS 구성 요소 시리즈-자신의 JS 구성 요 소 를 봉인 합 니 다. 에 소개 한 ajax 의 error 사건 을 추가 하 는 공공 처리 방법 을 기억 하 십 니까?우리 도 같은 메커니즘 을 통 해 이것 을 늘 릴 수 있 을 까?새 파일 Jqueryajax_extention.js
    
    (function ($) {
     //1.  $.ajax   
     var _ajax = $.ajax;
     $.ajax = function (options) {
      //2.      ajax          error    
      var fn = {
       error: function (XMLHttpRequest, textStatus, errorThrown) {
        toastr.error(XMLHttpRequest.responseText, '    ', { closeButton: true, timeOut: 0, positionClass: 'toast-top-full-width' });
       },
       success: function (data, textStatus) { },
       beforeSend: function (XHR) { },
       complete: function (XHR, TS) { }
      }
      //3.     $.ajax  ,       
      var _options = $.extend({}, {
       error: function (XMLHttpRequest, textStatus, errorThrown) {
        fn.error(XMLHttpRequest, textStatus, errorThrown);
       },
       success: function (data, textStatus) {
        fn.success(data, textStatus);
       },
       beforeSend: function (XHR) {
        XHR.setRequestHeader('Authorization', 'BasicAuth ' + Ticket);
        fn.beforeSend(XHR);
       },
       complete: function (XHR, TS) {
        fn.complete(XHR, TS);
       }
      }, options);
      //4.        ajax  
      _ajax(_options);
     };
    })(jQuery);
    이 js 를 참조 한 후 ajax 를 보 내 면 모든 요청 의 beforeSend 에 쓸 필요 가 없습니다.
    총화
    이상 은 하나의 사례 를 결합 하여 Basic 인증 의 실현 원리 와 간단 한 사용 을 설명 했다.본 고 는 모두 블 로 거 자신의 이해 에서 나 온 것 이 고 전면적 이지 않 은 부분 이 있 으 면 원 림 친구 들 이 고 쳐 주 기 를 기대한다.만약 본문 이 많 든 적 든 너 를 도 울 수 있다 면,추천 을 도와 도 무방 하 다.
    이상 의 C\#진급 시리즈 WebApi 인증 솔 루 션 추천:Basic 기초 인증 은 바로 편집장 이 여러분 에 게 공유 한 모든 내용 입 니 다.여러분 에 게 참고 가 될 수 있 고 많은 응원 을 바 랍 니 다.

    좋은 웹페이지 즐겨찾기