2012-08-16 22 views
9

के लिए भूमिका आधारित प्राधिकरण कैसे करें मैं एक सुरक्षित एएसपीनेट वेब एपीआई बनाने की कोशिश कर रहा हूं। कि मैं नीचे दिए गए लिंकएएसपीनेट एमवीसी 4 वेब एपीआई

MessageHandler for token

का पालन किया है तो अब हर api अनुरोध एक टोकन जो मैं नीचे के रूप में उदाहरण के लिए

public class TestController : Controller 
{ 

    public string GetProducts() 
    { 
     Uri myUri = new Uri("http://localhost:420420/api/products"); 
     WebRequest myWebRequest = WebRequest.Create(myUri); 

     myWebRequest.Method = "GET"; 
     myWebRequest.ContentType = "application/json"; 
     myWebRequest.Headers.Add("Authorization-Token", RSAClass.accessToken); 

     using (WebResponse response = myWebRequest.GetResponse()) 
     { 
      using (var responseStream = response.GetResponseStream()) 
      { 
       var reader = new StreamReader(responseStream); 
       return reader.ReadToEnd(); 
      } 
     } 
    }  
    } 

तो मैं अब कर रहा हूँ अनुरोध हेडर में आपूर्ति कर रहा हूँ की जरूरत है प्रत्येक एपीआई अनुरोध करने में सक्षम, शीर्षलेख में टोकन की जांच करें। लेकिन मैं प्रमाणीकरण कैसे पूरा कर सकता हूं, मेरा मतलब है कि मैं इस टोकन को उसी नियंत्रक में कुछ कार्रवाइयों तक नहीं पहुंचने की अनुमति कैसे दे सकता हूं। मुझे बस एक विचार चाहिए। आशा है कि मैंने काफी अच्छी तरह समझाया है।

संपादित करें:

public class TestController : Controller 
{ 
    public string GetProducts() 
    { 
     Uri myUri = new Uri("http://localhost:420420/api/products");   

     WebRequest myWebRequest = WebRequest.Create(myUri); 

     myWebRequest.Method = "GET"; 
     myWebRequest.ContentType = "application/json"; 
     myWebRequest.Headers.Add("Authorization-Token", RSAClass.accessToken); 

     **using (WebResponse response = myWebRequest.GetResponse()) 
     { 
      using (var responseStream = response.GetResponseStream()) 
      { 
       var reader = new StreamReader(responseStream); 
       return reader.ReadToEnd(); 
      } 
     }** 
} 

मैं, "API" नियंत्रक के लिए एक अनुरोध बनाने रहा नियंत्रक ऊपर अंदर, webrequest का उपयोग कर (मैं इसे बाद में HttpClient में बदल जाएगा)। के बीच ** ** ऊपर मैं myWebRequest.GetResponse() के लिए नहीं मिला 404 पृष्ठ हो रही है

नीचे delegating हैंडलर में अब मेरी एपीआई नियंत्रक

public class ProductsController : ApiController 
{ 

    TestModelContainer testModel = new TestModelContainer(); 

    [Authorize(Roles="Users")] 
    public IEnumerable<Products> GetProducts() 
    { 
     IEnumerable<Products> products = (from prods in testModel.Products 
         select prods); 
     return products;   
    }   
} 
} 

है मैं कोड में कोड

public class TokenValidationHandler : DelegatingHandler 
{ 
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, 
    CancellationToken cancellationToken) 
    { 
     TestModelContainer testModel = new TestModelContainer(); 

     var token = ""; 
     try 
     { 

      if (request.Headers.Contains("Authorization-Token")) 
      { 

       token = request.Headers.GetValues("Authorization-Token").FirstOrDefault(); 

       if (String.IsNullOrEmpty(token)) 
       { 
        return Task<HttpResponseMessage>.Factory.StartNew(() => 
        { 
         return new HttpResponseMessage(HttpStatusCode.BadRequest) 
         { 
          Content = new StringContent("Missing Authorization-Token") 
         }; 
        }); 
       } 
      } 
      else 
      { 
       return Task<HttpResponseMessage>.Factory.StartNew(() => 
       { 
        return new HttpResponseMessage(HttpStatusCode.BadRequest) 
        { 
         Content = new StringContent("You need to include Authorization-Token " + 
         "header in your request") 
        }; 
       }); 
      } 


      var decryptedToken = RSAClass.Decrypt(token); 
      var foundUser = (from user in testModel.Users 
           where user.Name == decryptedToken 
           select user).Any();    

      if (!foundUser) 
       return Task<HttpResponseMessage>.Factory.StartNew(() => 
       { 
        return new HttpResponseMessage(HttpStatusCode.Forbidden) 
        { 
         Content = new StringContent("Unauthorized User") 
        }; 
       }); 

     var identity = new GenericIdentity(decryptedToken); 
       string[] roles = new string[] { "Users", "Testers" }; 

       var principal = new GenericPrincipal(identity, roles); 
       Thread.CurrentPrincipal = principal; 
     } 
     catch (Exception ex) 
     { 
      return Task<HttpResponseMessage>.Factory.StartNew(() => 
      { 
       return new HttpResponseMessage(HttpStatusCode.InternalServerError) 
       { 
        Content = new StringContent("Error encountered while attempting to process authorization token") 
       }; 
      }); 
     } 
     return base.SendAsync(request, cancellationToken); 
    } 

404 त्रुटि वृद्धि नहीं करता है अगर मैं एपीआई नियंत्रक से अधिकृत विशेषता निकालने के लिए, और फिर मैं इसे का उपयोग करने में सक्षम हूँ के बाद।

अद्यतन (मेरा मानना ​​है कि समाधान भी):

यह कैसे समस्या हल हो जाती गया

मैं TestController विधि बदल गया है नीचे के रूप में सुझाव दिया डैरिन दिमित्रोव

public class TestsController : Controller 
{ 
    public ActionResult GetProducts() 
    { 
     var productsUrl = Url.RouteUrl("DefaultApi", new { httproute = "", controller = "products" }, "http"); 
     using (var client = new HttpClient()) 
     { 
      client.DefaultRequestHeaders.Add("Authorization-Token", RSAClass.accessToken); 

     var products = client 
       .GetAsync(productsUrl) 
       .Result; 

      if (products.StatusCode == HttpStatusCode.Unauthorized) 
      { 
       return Content("Sorry you are not authorized to perform this operation"); 
      } 

      var prods = products.Content 
       .ReadAsAsync<IEnumerable<Products>>() 
       .Result; 

      return Json(prods, JsonRequestBehavior.AllowGet); 
     } 
    } 

कर रहा है मुद्दा यह था कि मुझे एपीआई को कॉल करने का तरीका नहीं पता था, धन्यवाद डरिन उनके महान समर्थन के लिए (वह बहुत जल्दी था)।

धन्यवाद

उत्तर

26

आप Global.asax में हैंडलर रजिस्टर:

GlobalConfiguration 
    .Configuration 
    .MessageHandlers 
    .Add(new TokenValidationHandler()); 

और फिर नियंत्रक/कार्रवाई है कि [Authorize] विशेषता के साथ प्राधिकरण की आवश्यकता को सजाने:

public class MyController : ApiController 
{ 
    [Authorize] 
    public string Get(string id) 
    { 
     ...   
    } 
} 

भूमिका के लिए आधारित प्रमाणीकरण आप देख सकते हैं उदाहरण के लिए: https://stackoverflow.com/a/11536349/29407

यह एसएसएल पर मूल प्रमाणीकरण का उपयोग करता है और अंतर्निहित सदस्यता और भूमिका प्रदाताओं पर निर्भर करता है।


अद्यतन:

कई टिप्पणियों के अनुसार मैं धारणा है कि मेरा उत्तर पर्याप्त स्पष्ट नहीं था पाने के लिए छोड़ दिया। मुझे विस्तार से बताएं।

public class Product 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 
  • एक ApiController परिभाषित करें::

    public class ProductsController : ApiController 
    { 
        // GET /api/products => only users having the Users role can call this 
        [Authorize(Roles = "Users")] 
        public HttpResponseMessage Get() 
        { 
         var products = Enumerable.Range(1, 5).Select(x => new Product 
         { 
          Id = x, 
          Name = "product " + x 
         }); 
         return Request.CreateResponse(HttpStatusCode.OK, products); 
        } 
    
        // GET /api/products => only users having the Admin role can call this 
        [Authorize(Roles = "Admin")] 
        public void Post(Product product) 
        { 
        } 
    } 
    
  • को परिभाषित RSAHelper

    1. एक नया ASP.NET MVC 4 खाली टेम्पलेट का उपयोग कर परियोजना एक मॉडल बनाएं
    2. को परिभाषित करें :

      public class RSAClass 
      { 
          private static string _privateKey = "<RSAKeyValue><Modulus>poQS/c9tLkgg84xYZpnUBHP6fy24D6XmzhQ8yCOG317hfUNhRt6Z9N4oTn+QcOTh/DAnul4Q901GrHbPrMB8tl1LtbpKbvGftPhyR7OLQVnWC1Oz10t2tHEo7mqyPyAVuYsq8Q1E3YNTh2V6+PRvMiAWGUHGyyG7fKjt/R9W+RE=</Modulus><Exponent>AQAB</Exponent><P>4G09wYejA4iLakpAcjXbE/zV9tXTNsYqVIWeXF4hzwMmwmin7ru/WQzXu2DdapXXOJIKqrkfzXlcPwCsW5b9rQ==</P><Q>vfEq13Et+cP4eGgsR+crDQH0Mi+G6UW5ACfuDs/zam1o+CE70pLgeWawfqW4jRN30/VHDnTF9DZuotH6zihNdQ==</Q><DP>JoZaHYidERQ1am+IlJJuIwY57H9UHIjz50JwpsZ540FVO/YfLboI5M5xkfbUy2EhatKXBit1LB5zGVWSQL6wmQ==</DP><DQ>Gxk7KX2GN6oT2unR13hNlg9/TWGmd8VwvWr09bwJWFe/sBbduA8oY2mZKJhwGgB7CgxmVNOoIk1Zv3UBuUPauQ==</DQ><InverseQ>ZwJpSUZ09lCfiCF3ILB6F1q+6NC5hFH0O4924X9B4LZ8G4PRuudBMu1Yg0WNROUqVi3zfihKvzHnquHshSL56A==</InverseQ><D>pPQNRDVpeQGm8t1C7VDRwR+LNNV7krTMMbXGiJT5FOoPAmHvSZ9WcEZrM2gXFF8IpySlFm/86p84tbx0+jMs1niU52VsTscsamGbTzbsxeoHAt1fQUvzYveOGoRezotXblboVB2971r6avMHNtAk0FAdjvh4TjGZJCGTqNHD0mE=</D></RSAKeyValue>"; 
          private static string _publicKey = "<RSAKeyValue><Modulus>poQS/c9tLkgg84xYZpnUBHP6fy24D6XmzhQ8yCOG317hfUNhRt6Z9N4oTn+QcOTh/DAnul4Q901GrHbPrMB8tl1LtbpKbvGftPhyR7OLQVnWC1Oz10t2tHEo7mqyPyAVuYsq8Q1E3YNTh2V6+PRvMiAWGUHGyyG7fKjt/R9W+RE=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>"; 
          private static UnicodeEncoding _encoder = new UnicodeEncoding(); 
      
          public static string Decrypt(string data) 
          { 
           try 
           { 
            var rsa = new RSACryptoServiceProvider(); 
            var dataArray = data.Split(new char[] { ',' }); 
      
            byte[] dataByte = new byte[dataArray.Length]; 
            for (int i = 0; i < dataArray.Length; i++) 
            { 
             dataByte[i] = Convert.ToByte(dataArray[i]); 
            } 
      
            rsa.FromXmlString(_privateKey); 
            var decryptedByte = rsa.Decrypt(dataByte, false); 
            return _encoder.GetString(decryptedByte); 
           } 
           catch (Exception) 
           { 
            throw new RSAException(); 
           } 
          } 
      
          public static string Encrypt(string data) 
          { 
           try 
           { 
            var rsa = new RSACryptoServiceProvider(); 
            rsa.FromXmlString(_publicKey); 
            var dataToEncrypt = _encoder.GetBytes(data); 
            var encryptedByteArray = rsa.Encrypt(dataToEncrypt, false).ToArray(); 
            var length = encryptedByteArray.Count(); 
            var item = 0; 
            var sb = new StringBuilder(); 
            foreach (var x in encryptedByteArray) 
            { 
             item++; 
             sb.Append(x); 
      
             if (item < length) 
              sb.Append(","); 
            } 
      
            return sb.ToString(); 
      
           } 
           catch (Exception ex) 
           { 
            throw new RSAException(); 
           } 
          } 
      
          public class RSAException : Exception 
          { 
           public RSAException() : base("RSA Encryption Error") { } 
          } 
      } 
      
    3. को परिभाषित TokenValidationHandler:

      public class TokenValidationHandler : DelegatingHandler 
      { 
          protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
          { 
           try 
           { 
            if (!request.Headers.Contains("Authorization-Token")) 
            { 
             return Task<HttpResponseMessage>.Factory.StartNew(() => 
             { 
              return new HttpResponseMessage(HttpStatusCode.BadRequest) 
              { 
               Content = new StringContent("You need to include Authorization-Token header in your request") 
              }; 
             }); 
            } 
      
            var token = request.Headers.GetValues("Authorization-Token").FirstOrDefault(); 
            if (string.IsNullOrEmpty(token)) 
            { 
             return Task<HttpResponseMessage>.Factory.StartNew(() => 
             { 
              return new HttpResponseMessage(HttpStatusCode.BadRequest) 
              { 
               Content = new StringContent("Missing Authorization-Token") 
              }; 
             }); 
            } 
      
            var decryptedToken = RSAClass.Decrypt(token); 
      
            // TODO: do your query to find the user 
            var user = decryptedToken; 
      
            var identity = new GenericIdentity(decryptedToken); 
            string[] roles = new[] { "Users", "Testers" }; 
      
            var principal = new GenericPrincipal(identity, roles); 
            Thread.CurrentPrincipal = principal; 
           } 
           catch 
           { 
            return Task<HttpResponseMessage>.Factory.StartNew(() => 
            { 
             return new HttpResponseMessage(HttpStatusCode.InternalServerError) 
             { 
              Content = new StringContent("Error encountered while attempting to process authorization token") 
             }; 
            }); 
           } 
      
           return base.SendAsync(request, cancellationToken); 
          } 
      } 
      
    4. एक परीक्षण नियंत्रक को परिभाषित करें:

      public class TestsController : Controller 
      { 
          public ActionResult GetProducts() 
          { 
           var productsUrl = Url.RouteUrl("DefaultApi", new { httproute = "", controller = "products" }, "http"); 
           using (var client = new HttpClient()) 
           { 
            var token = RSAClass.Encrypt("john"); 
            client.DefaultRequestHeaders.Add("Authorization-Token", token); 
      
            var products = client 
             .GetAsync(productsUrl) 
             .Result 
             .Content 
             .ReadAsAsync<IEnumerable<Product>>() 
             .Result; 
      
            return Json(products, JsonRequestBehavior.AllowGet); 
           } 
          } 
      
          public ActionResult PostProduct() 
          { 
           var productsUrl = Url.RouteUrl("DefaultApi", new { httproute = "", controller = "products" }, "http"); 
           using (var client = new HttpClient()) 
           { 
            var token = RSAClass.Encrypt("john"); 
            client.DefaultRequestHeaders.Add("Authorization-Token", token); 
      
            var product = new Product 
            { 
             Id = 1, 
             Name = "test product" 
            }; 
      
            var result = client 
             .PostAsync<Product>(productsUrl, product, new JsonMediaTypeFormatter()) 
             .Result; 
            if (result.StatusCode == HttpStatusCode.Unauthorized) 
            { 
             return Content("Sorry you are not authorized to perform this operation"); 
            } 
      
            return Json(true, JsonRequestBehavior.AllowGet); 
           } 
          } 
      } 
      
    5. टेस्ट:

      * /tests/getproducts => success 
      * /tests/postproduct => 401 
      
  • +0

    मैं पहले से ही TokenValidation पंजीकृत किया है global.asax.cs में, लेकिन मेरा सवाल मैं एक प्रमाणीकृत टोकन कैसे बना सकता हूं, उसी नियंत्रक में कुछ अन्य कार्रवाइयों तक नहीं पहुंच सकता ...? मेरा मतलब है कि मैं "एपीआई नियंत्रक" – CrazyNooB

    +0

    में जेनरेट किए गए टोकन के साथ [प्राधिकरण (भूमिकाएं = "व्यवस्थापक")] कैसे पूरा करूं, आपको एक अलग 'टोकन वैलिडेशन हैंडलर' लिखना होगा। इस आलेख में प्रस्तुत किया गया केवल टोकन के अंदर उपयोगकर्ता नाम स्टोर करता है, बिल्कुल कोई भूमिका नहीं। आप निम्नलिखित उत्तर की जांच कर सकते हैं जिसमें मैंने बुनियादी प्रमाणीकरण योजना का उपयोग करके एक कस्टम प्रतिनिधि हैंडलर और अंतर्निहित सदस्यता और भूमिका प्रदाताओं पर भरोसा किया है: http://stackoverflow.com/a/11536349/29407 –

    +0

    बिल्कुल वही है जो मैं पूछ रहा था । क्या आप कोड का मामूली टुकड़ा दे सकते हैं कि टोकन के साथ भूमिका आधारित प्राधिकरण कैसे करें ..? – CrazyNooB

    संबंधित मुद्दे