How to use ASP. NET Web Api to build a REST-style service? series of tutorials [8]-Web Api Security

Source: Internet
Author: User

Preface this article mainly discusses the security of Web APIs. So far, all requests are based on the Http protocol (http ://), therefore, the communication between the client and the server is not encrypted. In this article, we will add the authentication function in StudentController-verify the user name and password to determine whether the user is a legal user. As we all know, we should use secure Http protocol (https: //) for the transmission of confidential information ://) to force Https transfer in Web APIs. We can configure the entire Web Api at the IIS level to force Https, but in some cases you may only need to force Https for a specific action, other methods still use http. To achieve this, we will use filters -- filter (filter) in the Web Api to execute a piece of code before we execute the method. If you have never touched the filter, you can skip this step. The Untitled filter is used to check whether it is secure. If it is not secure, the filter will terminate the request and return the corresponding result: the request must be https. Practice: Create a filter that inherits from AuthorizationFilterAttribute and override OnAuthorization to meet our requirements. Create a "Filters" folder under the root directory of the website, and create a class "ForceHttpsAttribute" inherited from "System. web. http. filters. authorizationFilterAttribute ", the following code: copy the code public class ForceHttpsAttribute: AuthorizationFilterAttribute {public override void OnAuthorization (System. web. http. controllers. httpActionContext actionContext) {var request = actionContext. request; if (request. requestUri. scheme! = Uri. uriSchemeHttps) {var html = "<p> Https is required </p>"; if (request. method. method = "GET") {actionContext. response = request. createResponse (HttpStatusCode. found); actionContext. response. content = new StringContent (html, Encoding. UTF8, "text/html"); UriBuilder httpsNewUri = new UriBuilder (request. requestUri); httpsNewUri. scheme = Uri. uriSchemeHttps; httpsNewUri. port = 443; actionContext. res Ponse. headers. location = httpsNewUri. uri;} else {actionContext. response = request. createResponse (HttpStatusCode. notFound); actionContext. response. content = new StringContent (html, Encoding. UTF8, "text/html") ;}}} copy the code in the above Code, we get the request and response objects through the actionContext parameter, and we determine the client request: if it is not https, therefore, you should use https to directly respond to the client. Here, we need to distinguish whether the request is Get or other (Post, Delete, Put), because for Get requests that use Http to access resources, we will use https to create a connection and add it to the Location of the response Header. After this is done, the client will automatically Use https to send the Get request. For non-Get requests, 404 is directly returned, and the client must be notified to Use https for requests. If we intend to use this in the entire project, make the following settings in the "WebAPIConfig" class: public static void Register (HttpConfiguration config) {config. filters. add (new ForceHttpsAttribute ();} if we set the Controller or Action, we can make the following settings: copy the code // force Https [Learning for the entire Controller. web. filters. forceHttps ()] public class CoursesController: BaseApiController {// only force Https [Learning for this method. web. filters. forceHttps ()] public H TtpResponseMessage Post ([FromBody] CourseModel courseModel) {}} copies the code using Basic Authentication to verify that all the APIS we provide so far are public and accessible to anyone. However, it is not desirable in real scenarios. For some data, only authenticated users can access it. Here we have two points to illustrate this: 1. when the client sends the Get request "http: // {your_port}/api/students/{userName. for example, if userNme is "TaiseerJoudeh" accessed through the URI above, we must allow the client to provide the corresponding username and password for TaiseerJoudeh. If no authentication information is provided, we will not allow access, because student information contains important personal information (such as email and birthday ). 2. when the client sends a Post request to "http: // {your_port}/api/courses/2/students/{userName}", this means selecting courses for students, we can think about it. If no verification is performed here, then everyone can select a course for a student. Isn't it messy. In the preceding scenario, we use Basic Authentication for identity Authentication. The main idea is to use filter to obtain identity information from the request header, check whether the Authentication type is "basic", and then verify the content, if it is correct, it is allowed. Otherwise, the 401 (Unauthorized) status code is returned. Before running the code, explain basic authentication: What is basic authentication? It indicates that the identity of the requester is verified before the Http request is formally processed, which can prevent the server from DoS attacks (Denial of service attacks ). The principle is: when the client sends an Http request, it provides a Base64-encoded user name and password in the Header, in the form of "username: password", and the message receiver (server) for verification, after the request is passed, the request is processed. Because the user name and password are only base64 encoded, to ensure security, basic authentication is generally based on SSL connections (https) for use in our api, create a class "LearningAuthorizeAttribute" inherited from System. web. http. filters. authorizationFilterAttribute: AuthorizationFilterAttribute {[Inject] public LearningRepository TheRepository {get; set;} public override void OnAuthorization (System. web. http. controllers. httpActionContext actionC Ontext) {// forms authentication Case that user is authenticated using forms authentication // so no need to check header for basic authentication. if (Thread. currentPrincipal. identity. isAuthenticated) {return;} var authHeader = actionContext. request. headers. authorization; if (authHeader! = Null) {if (authHeader. Scheme. Equals ("basic", StringComparison. OrdinalIgnoreCase )&&! String. isNullOrWhiteSpace (authHeader. parameter) {var credArray = GetCredentials (authHeader); var userName = credArray [0]; var password = credArray [1]; if (IsResourceOwner (userName, actionContext )) {// You can use Websecurity or asp.net memebrship provider to login, for // for he sake of keeping example simple, we used out own login functionality if (TheRepository. loginStudent (userName, password) {var currentPrincipal = new GenericPrincipal (new GenericIdentity (userName), null); Thread. currentPrincipal = currentPrincipal; return ;}}} HandleUnauthorizedRequest (actionContext);} private string [] GetCredentials (System. net. http. headers. authenticationHeaderValue authHeader) {// Base 64 encoded string var rawCred = authHeader. parameter; var encoding = Encoding. getEncoding ("iso-8859-1"); var cred = encoding. getString (Convert. fromBase64String (rawCred); var credArray = cred. split (':'); return credArray;} private bool IsResourceOwner (string userName, System. web. http. controllers. httpActionContext actionContext) {var routeData = actionContext. request. getRouteData (); var resourceUserName = routeData. values ["userName"] as string; if (resourceUserName = userName) {return true;} return false;} private void HandleUnauthorizedRequest (System. web. http. controllers. httpActionContext actionContext) {actionContext. response = actionContext. request. createResponse (HttpStatusCode. unauthorized); actionContext. response. headers. add ("WWW-Authenticate", "Basic Scheme = 'elearning' location =' http://localhost:8323/account/login '") ;}} Copy the code. We have rewritten" OnAuthorization "to implement the following functions: 1. obtain the verification data from the request Header. verify that the verification information type is "basic" and contains base64 encoding 3. encodes base64 into a string and extracts the username and password. check whether the provided verification information is the same as the accessed resource information (the student's detailed information can only be accessed by himself. verify the username and password in the database. 6. if the verification succeeds, set the CurrentPrincipal of the Thread so that all subsequent requests are verified. 7. if the verification fails, the system returns 401 (Unauthorized) and adds a WWW-Authenticate response header. Based on this request, the client can add the corresponding verification information to implement it in the code, the last two attributes are complete: copy the code public class StudentsController: BaseApiController {[LearningAuthorizeAttribute] public HttpResponseMessage Get (string userName) {}} copy the code public class EnrollmentsController: baseApiController {[LearningAuthorizeAttribute] public HttpResponseMessage Post (int courseId, [FromUri] string userName, [FromBody] Enrollment enrollment ){}}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.