本章讨论创建安全的WebApi服务,到目前为止,我们实现的API都是基于未加密的HTTP协议,大家都知道在Web中传递身份信息必须通过HTTPS,接下来我们来实现这一过程。
其实可以通过IIS配置,将整个WebApi的访问都配置为Https,但实际上,如果希望只是对部分方法进行认证,那就必须通过认证身份信息进行处理。
下面介绍通过Filter来实现这一过程,如果身份认证不通过,就返回一条信息,提示访问者通过https进行访问。
1: public class ForceHttpsAttribute : AuthorizationFilterAttribute
2: {3: public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
4: { 5: var request = actionContext.Request; 6: 7: if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
8: {9: var html = "<p>Https is required</p>";
10: 11: if (request.Method.Method == "GET")
12: { 13: actionContext.Response = request.CreateResponse(HttpStatusCode.Found);14: actionContext.Response.Content = new StringContent(html, Encoding.UTF8, "text/html");
15: 16: UriBuilder httpsNewUri = new UriBuilder(request.RequestUri);
17: httpsNewUri.Scheme = Uri.UriSchemeHttps; 18: httpsNewUri.Port = 443; 19: 20: actionContext.Response.Headers.Location = httpsNewUri.Uri; 21: }22: else
23: { 24: actionContext.Response = request.CreateResponse(HttpStatusCode.NotFound);25: actionContext.Response.Content = new StringContent(html, Encoding.UTF8, "text/html");
26: } 27: 28: } 29: } 30: }通过actionContext参数获取Request和Response对象,对URI进行检查,如果不是以HTTPS开头,就返回443代码。
使用的方法有两种,一种是在WebAPIConfig中注册为全局的Attribute。
1: public static void Register(HttpConfiguration config)
2: {3: config.Filters.Add(new ForceHttpsAttribute());
4: }另一种是对制定的类或者方法进行拦截。
1: //Enforce HTTPS on the entire controller
2: [Learning.Web.Filters.ForceHttps()]3: public class CoursesController : BaseApiController
4: {5: //Enforce HTTPS on POST method only
6: [Learning.Web.Filters.ForceHttps()]7: public HttpResponseMessage Post([FromBody] CourseModel courseModel)
8: { 9: 10: } 11: }当前所有的API都是Public的,网络上的任意用户都可以请求资源。实际的项目中肯定要对访问者进行必要的限制。
Basic Authentication提供了一种在Http Request被处理之前先行进行身份认证的模式,它在防止Dos等方面具有重要作用。Basic Authentication要求在请求时必须在Http Header提供基于Base64编码的用户名和密码信息。这种认证一般应该通过HTTPS来实现。
1: public class LearningAuthorizeAttribute : AuthorizationFilterAttribute
2: { 3: 4: [Inject]5: public LearningRepository TheRepository { get; set; }
6: 7: public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
8: {9: //Case that user is authenticated using forms authentication
10: //so no need to check header for basic authentication.
11: if (Thread.CurrentPrincipal.Identity.IsAuthenticated)
12: {13: return;
14: } 15: 16: var authHeader = actionContext.Request.Headers.Authorization; 17: 18: if (authHeader != null)
19: {20: if (authHeader.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) &&
21: !String.IsNullOrWhiteSpace(authHeader.Parameter)) 22: { 23: var credArray = GetCredentials(authHeader); 24: var userName = credArray[0]; 25: var password = credArray[1]; 26: 27: if (IsResourceOwner(userName, actionContext))
28: {29: //You can use Websecurity or asp.net memebrship provider to login, for
30: //for he sake of keeping example simple, we used out own login functionality
31: if (TheRepository.LoginStudent(userName, password))
32: {33: var currentPrincipal = new GenericPrincipal(new GenericIdentity(userName), null);
34: Thread.CurrentPrincipal = currentPrincipal;35: return;
36: } 37: } 38: } 39: } 40: 41: HandleUnauthorizedRequest(actionContext); 42: } 43: 44: private string[] GetCredentials(System.Net.Http.Headers.AuthenticationHeaderValue authHeader)
45: { 46: 47: //Base 64 encoded string
48: var rawCred = authHeader.Parameter;49: var encoding = Encoding.GetEncoding("iso-8859-1");
50: var cred = encoding.GetString(Convert.FromBase64String(rawCred)); 51: 52: var credArray = cred.Split(‘:‘);
53: 54: return credArray;
55: } 56: 57: private bool IsResourceOwner(string userName, System.Web.Http.Controllers.HttpActionContext actionContext)
58: { 59: var routeData = actionContext.Request.GetRouteData();60: var resourceUserName = routeData.Values["userName"] as string;
61: 62: if (resourceUserName == userName)
63: {64: return true;
65: }66: return false;
67: } 68: 69: private void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
70: { 71: actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized); 72: 73: actionContext.Response.Headers.Add("WWW-Authenticate",
74: "Basic Scheme=‘eLearning‘ location=‘http://localhost:8323/account/login‘");
75: 76: } 77: }上述代码实现了以下逻辑:
现在可以对指定的方法进行标记。
1: public class StudentsController : BaseApiController
2: { 3: [LearningAuthorizeAttribute]4: public HttpResponseMessage Get(string userName)
5: { 6: 7: } 8: } 9: 10: public class EnrollmentsController : BaseApiController
11: { 12: [LearningAuthorizeAttribute]13: public HttpResponseMessage Post(int courseId, [FromUri]string userName, [FromBody]Enrollment enrollment)
14: { 15: 16: } 17: }现在分别用FireFox和Fiddler进行测试。假设路径如下:http://localhost:{your_port}/api/students/TaiseerJoudeh。
[翻译]创建ASP.NET WebApi RESTful 服务(8),布布扣,bubuko.com
[翻译]创建ASP.NET WebApi RESTful 服务(8)
原文:http://www.cnblogs.com/tukzer/p/3662521.html