Hướng dẫn asp.net core 2.0 mvc
TL;DR: ASP.NET Core, the rewritten, cross-platform, and open source version of ASP.NET framework is gaining popularity for being easy to use and for having great performance when compared to modern solutions like Java, Go and Node.js. In this article we are going to use ASP.NET Core to create a simple RESTful API that handles grocery lists and then we are going to add authentication to secure this API. Show
"Creating secure RESTful APIs with ASP.NET Core is a piece of cake." What is ASP.NET CoreASP.NET Core is an open source redesign of the popular ASP.NET framework. This new version was developed to support modern cloud based applications, such as web applications, Internet of Things (IoT) devices, and mobile backends. There are a few differences between ASP.NET Core and its predecessor, the first big one is that the new version is cross-platform and can run on Windows, Mac and Linux. Another big difference is that ASP.NET Core is fully open source and available on GitHub. ASP.NET Core vs ASP.NET FrameworkAs mentioned, ASP.NET Core is a new framework and, as such, it has much less support and libraries available than its predecessor. Microsoft has written a good article where it exposes when to use the new framework and when to use the old one. Basically, it says that developers should keep using the older version when they depend on third-party .NET libraries or NuGet packages that are not available for .NET Core, or when they are extending existing .NET applications. This article also highlights that the following use cases are better fitted with .NET Core:
Tweet ThisInstalling .NET CoreThe process to install .NET Core and to start developing applications depends on what platform we are going to use (i.e. Windows, Mac, or Linux). As I use Mac, I will show instructions on how to install it in this platform, but if you use or , please follow the instructions on Microsoft's web page before moving along. .NET Core, on a Mac OS device, depends on the latest version of OpenSSL. To install it we will use Homebrew. If you already have Homebrew installed locally, just issue the following commands. If you don't, please install it first.
After updating OpenSSL locally, you will have to download the .NET Core SDK and install it. Having the SDK installed, you can check if everything is in place by issuing the following command:
Creating the ASP.NET Core AppTo bootstrap an ASP.NET Core application, we are going to create a new folder called
8, and use
9 CLI (command line interface) to assemble the project structure. To do so, let's issue the following commands:
This process, which shall take just a few seconds, will produce a structure that contains the following directories and files (a few resources were omitted for the sake of brevity):
During this article we are going to focus basically on the
0 directory, where we will create RESTful controllers, and on the
1 class, which is responsible for starting our API and configuring the services that we are going to use. Creating the Grocery List APIWhenever a user wants to manage their grocery list, they will issue HTTP requests to our API. These HTTP requests are going to be handled by a new controller that we are going to create. To persist the grocery list items, this controller will interact with a database. Therefore we are going to need three new classes:
2, which will act as the persistence layer;
3, which will be the model that represents the items in our application; and
4, which will handle the HTTP requests issued by users. Creating the Grocery Item ModelOur model will be quite simple, it will contain only an
5, which will be used to identify it, and a
6. Let's start by creating a
7 directory in the root path of our application, and then let's create a file called
8 on it. This new file will contain the following code:
Adding a Persistence LayerAs mentioned, we will use an in-memory database to persist our grocery list's items. Therefore, let's start by adding the
9 package to our project by issuing the following command:
After that we will create the
2 class, which will handle the persistence features. This class will be created in the same
7 directory, and will have the following code:
Handling HTTP RequestsHandling HTTP requests with ASP.NET Core is a piece of cake. As we will see in the source code of the
4 class, there are four attributes that we can add to methods that handle HTTP requests:
We won't use the last attribute (
6 attribute to the method responsible for the update. Another useful attribute is
9. This attribute is used to automatically deserialize method parameters from the body part of a HTTP request. In this article we are going to use this attribute to automatically transform a
3 from JSON to an object instance. Now that we have a better understanding of what ASP.NET Core offers us, let's create the
4 class. This class will be create in the
2 file in the
0 directory, and will contain the following source code:
The last step that we need to perform to finish our (unauthenticated) grocery list application, is to configure the
2 to use the in-memory database package that we have added to our project. To do so, let's open the
1 file in the root directory of our application and change the
6 method as follows:
Having everything in place, we can now use the RESTful API to save new grocery items to our list, get the whole list, and delete existing items through their ids. The following commands show how to interact with the API by using curl.
The full source code of this application can be found in the
7 branch of this GitHub repository. Adding Authentication to ASP.NET CoreTo secure our ASP.NET Core application, we are going to rely on JWTs (JSON Web Tokens). JSON Web Token (JWT) is an open standard that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. The technology is becoming a de facto standard for securing microservices and backends for mobile applications and for SPA (Single Page Applications). Using JWTs to authenticate requests makes easier to create stateless applications and therefore to scale this applications horizontally. If you want to learn more about JWTs, take a look at this resource. To secure our application, we are going to start by installing three packages:
0 The first package, called JWT, will be used to issue JWTs to users signing in. The second one is the default package for handling Identity in ASP.NET Core applications, and will be integrated with our authentication solution. And the last package, JwtBearer, also provided by Microsoft, will be used to validate the tokens issued. Configuring JWT PropertiesTo start integrating these packages in our application, we will create three properties in the
8 file:
1 The first property,
9, is used to sign the tokens that our application will create, and also to validate tokens received. The
0 and
1 properties will be included in all tokens that we issue, and when we receive a token we will assure that this token contains these two claims (
2 for
0 and
4 for
1). Like that we can guarantee that the token was indeed issued for our grocery list application. To access these properties in our application, we are going to create a class called
6 in a new file in the root directory of our application:
2 As we can see, this class has the exact same properties added to the
8 file. To load the properties from the JSON file in an instance of this new class, add the following code as the first line of the
6 method of the
9 class:
3 Enabling User RegistrationThe next step is to create a class that will enable users to register in our application. This class will be created in a new file called
0 in the
1 directory, and will contain the following code:
4 This class, for the time being, contains only one public method,
2, which accepts HTTP POST requests with
3 in the body. Besides this public method, it contains the following private methods:
The
3 class accepted by the
2 method, has not been created yet, so let's do it now. Let's create a new file called
2 in the
7 directory and add the following code to it:
5 Whenever users successfully register themselves in our application, their credentials get persisted to the database. To enable this feature, we need to create a class that will act as the persistence layer. This class will be created in a new file called
4, in the
7 directory, with the following code:
6 And then we need to make two changes in the add the
9 class. First we need to add two lines, with the
7 statements, as the first two lines of the
6. And then we need to configure our app to use the identity framework:
7 After updating our application as explained above, we are now able to handle user registration. To check if everything is working as expected, let's start our application (which can be done through our IDE or through the
9 command), and issue the following HTTP POST request:
8 Note that the password must contain at least one number, one lowercase character, one uppercase character, one non alphanumeric character, and at least six characters. Just like the example above. If we managed to update our application accordingly, the answer to our request will be a JSON object with two properties:
8 and
9. Enabling Users to Sign InNow that our users are already able to create accounts on our ASP.NET Core application, we need to add a feature for the existing users to sign in. The sign in process is quite similar to the registration process, the difference is that when a user signs in, it won't be registered in the database. Its credentials are going to be used to query the database to see if a user with the email and password combination exists, and if it does, the
8 and
9 will be generated and sent back. To enable this feature, we are going to add the following method to the
04 class recently created:
9 To sign in into the application, we just need to issue an HTTP POST similar to the registration one. The difference is the endpoint URL, that now contains a
05 suffix:
0 Protecting ASP.NET Core APIEven though we have created the two endpoints to enable users to register and to sign in, our grocery list application API is still publicly available. To secure all endpoints exposed by the
4 class, we just need to add the
07 attribute to this class, like shown below:
1 If we start the application now, and issue an HTTP GET request to any endpoint of the
4 class, we will get a 404 (Not Found) response from the server. You would probably expect a 401 (Unauthorized) answer, but 404 was sent back because when a user is not logged in they are redirect to a login web page. This web page is not provided by default by ASP.NET Core, and therefore the request ends up being answered with a 404 response. To circumvent this behavior, we can configure the Identity framework in the
6 method of the
9 class as follows:
2 Although we have secured our precious endpoints, we are not ready yet. Even if we send the
8 in a HTTP request, we are still going to get a 401 answer, because we have not configured our application to validate JWTs. Let's tackle this issue now. Validating JWTs with ASP.NET CoreTo make our ASP.NET Core application validate the tokens issued by our register and sign in features, we are going to add just a few lines of code to the
12 method of the
9 class. Below is the full source code of this method after adding the lines that validate JWTs:
3 As you can see, we first have loaded the same configuration properties used to generate tokens, and then added a
14 call passing a
15 with these properties. With that we are now able to validate JWTs and enable (or block) users carrying these tokens to access the grocery list API. To test the endpoint with
16, you can issue the following commands:
4 Note that we have used If you need a reference for a ASP.NET Core application with authentication fully implemented, you can take a look at the
21 branch of this GitHub repository. "Creating secure RESTful APIs with ASP.NET Core is a piece of cake." Aside: Securing ASP.NET Core with Auth0In the following sections, we will see how to use authorization features of OAuth 2.0 to limit access to our ASP.NET Core applications. To learn more about OAuth 2.0, we can refer to the API authorization documentation. The very first thing we need is to create our own Auth0 account. Luckily, Auth0 has a free tier that supports 7,000 free active users & unlimited logins! Create a Resource Server (API)After creating the account, we need to register our application in . On this section, let's click "Create API". Then we have to provide a name ("Contacts API") and an identifier (
23. For the signing algorithm, let's select RS256. Installing DependenciesTo use tokens with ASP.NET Core applications, we need to use the JWT middleware. This middleware is provided by the
24 package. To install this package, let's use the
9 command:
5 ConfigurationAs requested when creating it, our API will use RS256 as the algorithm for signing tokens. Since RS256 uses a private/public key pair, it verifies the tokens against the public key for our Auth0 account. The ASP.NET Core JWT middleware will handle downloading the JSON Web Key Set (JWKS) file containing the public key for us, and will use that to verify the
8 signature. To add the JWT middleware to our application's middleware pipeline, let's go to the
12 method of our
9 class and add a call to
14. This call will pass in an instance of
15 configured with our Auth0 properties. The
15 needs to specify our Auth0 API Identifier as the
1, and the full path to our Auth0 domain as the
33:
6 The JWT middleware integrates with the standard ASP.NET Core Authentication and Authorization mechanisms. Therefore, to secure an endpoint we only need to decorate our controller action with the
34 attribute:
7 Creating an Auth0 ClientAs the focus of this section is to secure ASP.NET Core with Auth0, we are going to use a live Angular app that has a configurable Auth0 client. Before using this app, we need to create an Auth0 Client that represents it. Let's head to the and click on the "Create Client" button to create this client. On the popup shown, let's set the name of this new client as "Contacts Client" and choose "Single Page Web App" as the client type. After hitting the "Create" button, we have to go to the "Settings" tab of this client and add
35 to the "Allowed Callback URLs" field. Now we can save the client and head to the sample Angular app secured with Auth0. To use this app, we need to set the correct values for four properties:
Product Information:Version: 1.0.4Commit SHA-1 hash: af1e6684fdRuntime Environment:OS Name: Mac OS XOS Version: 10.12OS Platform: DarwinRID: osx.10.12-x64Base Path: /usr/local/share/dotnet/sdk/1.0.4 36: We have to copy this value from the "Client ID" field of the "Settings" tab of "Contacts Client".
37: We can also copy this value from the "Settings" tab of "Contacts Client".
Product Information:Version: 1.0.4Commit SHA-1 hash: af1e6684fdRuntime Environment:OS Name: Mac OS XOS Version: 10.12OS Platform: DarwinRID: osx.10.12-x64Base Path: /usr/local/share/dotnet/sdk/1.0.4 38: We have to set this property to meet the identifier of the API that we created earlier ( dotnet --info command output (example)#.NET Command Line Tools (1.0.4) Product Information:Version: 1.0.4Commit SHA-1 hash: af1e6684fdRuntime Environment:OS Name: Mac OS XOS Version: 10.12OS Platform: DarwinRID: osx.10.12-x64Base Path: /usr/local/share/dotnet/sdk/1.0.4 22).
40: This property will define the
41 that the
8 will get access to in the backend API. For example:
43 or both
44.Then we can hit the "Sign In with Auth0" button. After signing in, we can use the application to submit requests to our secured Node.js API. For example, if we issue a GET request to
45, the Angular app will include the
8 in the
47 header and our API will respond with a list of contacts. ConclusionDeveloping RESTful APIs with ASP.NET Core is easy and can lead to loosely coupled architectures with great performance and scalability. Also, the authentication feature was easy to implement and, with Auth0, can be easily enhanced. With these upsides, alongside with the fact that the whole .NET Core technology is open source and cross platform, we can expect an exponential growth on the interest for this framework, which will result on rich set of open source packages and a thriving community. Therefore, it is a good time to to learn ASP.NET Core and to start writing application with this solution. |