How to do role based authorization for asp.net mvc 4 web api

后端 未结 1 660
余生分开走
余生分开走 2020-12-04 15:09

I am trying to make a secure asp.net web api. For that I have followed the below link

MessageHandler for token

So now each and every api request needs a toke

相关标签:
1条回答
  • 2020-12-04 15:40

    You register the handler in Global.asax:

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

    and then decorate controllers/actions that require authorization with the [Authorize] attribute:

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

    For role based authorization you may could take a look at the following example: https://stackoverflow.com/a/11536349/29407

    It uses basic authentication over SSL and relies on the built-in membership and role providers.


    UPDATE:

    According to the numerous comments left I get the impression that my answer was not clear enough. Let me elaborate.

    1. Create a new ASP.NET MVC 4 project using the Empty Template
    2. Define a model:

      public class Product
      {
          public int Id { get; set; }
          public string Name { get; set; }
      }
      
    3. Define an 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)
          {
          }
      }
      
    4. Define a RSAHelper:

      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") { }
          }
      }
      
    5. Define a 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);
          }
      }
      
    6. Define a test controller:

      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);
              }
          }
      }
      
    7. Test:

      * /tests/getproducts => success
      * /tests/postproduct => 401
      
    0 讨论(0)
提交回复
热议问题