Securing ASP.NET Core 2.0 Applications with JWTs

Securing ASP.NET Core 2.0 Applications with JWTs

โหลดตัวอย่างมาจาก Git Using JWTs in .NET Core 2

เปิดขึ้นมาแล้วลองรัน
browser จะชี้ไปที่ http://localhost:63939/api/books ซึ่งจะ Error ดังนี้
This page isn’t working
If the problem continues, contact the site owner.
HTTP ERROR 401

แล้วถ้าเรียกไปที่ http://localhost:63939/api/token ก็จะ Error แบบนี้
This localhost page can’t be found
No webpage was found for the web address: http://localhost:63939/api/token
Search Google for localhost 63939 api token
HTTP ERROR 404

เป็นเพราะไม่ได้ส่งพารามิเตอร์ที่จำเป็นไปให้

ทีนี้ลองใช้ Postman เรียกไปที่ http://localhost:63939/api/token
พร้อมส่งค่าไปดังนี้

{
	"username": "mario", 
	"password": "secret"
}

จะได้ค่าคืนมาเป็นแบบข้างล่างนี้ก็เป็นอันใช้ได้

{
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJNYXJpbyBSb3NzaSIsImVtYWlsIjoibWFyaW8ucm9zc2lAZG9tYWluLmNvbSIsImJpcnRoZGF0ZSI6IjI1MjYtMDktMjMiLCJqdGkiOiJhYzdlYWRhZS02YzI4LTRlMDctOWM2OC1mMjAxMjNjYWY1OTUiLCJleHAiOjE1MzU1MzI2NTUsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NjM5MzkvIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo2MzkzOS8ifQ.dCmNVlejU4kjQI1NNZRbBPXZ19AKQmWwekHT8aSCAsY"
}

 

ASP.NET Core 2 provides native support to JSON Web Tokens.
In this article, we will take a look at how to enable JWTs when creating a Web API application based on ASP.NET Core 2.

A Quick Introduction to JWTs
JSON Web Tokens, often shortened with JWTs

The JWTs are structured in three sections:

  • the Header: this is a JSON object containing meta-information about the type of JWT and hash algorithm used to encrypt the data.
  • the Payload: even this is a JSON object containing the actual data shared between source and target; these data are coded in claims, that is statements about an entity, typically the user.
  • the Signature: this section allows to verify the integrity of the data, since it represents a digital signature based on the previous two sections.

JWT technology allows a client to store session data on its side and to provide the token to the server whenever it tries to access a protected resource. Usually, the token is sent to the server in the Authorization HTTP header using the Bearer schema, and it should contain all the information that allows to grant or deny access to the resource.

Securing ASP.NET Core 2.0 Applications with JWTs

สร้างโปรเจ็กส์แบบ ASP.NET Core Web Application
ชื่อโปรเจ็กส์ JWT เลือก API แบบ No Authen

ทดลองรันดู จะขึ้นหน้า https://localhost:44307/api/values
และคืนค่า

["value1","value2"]

Startup.cs
แก้ไขไฟล์ Startup.cs

appsettings.json
แก้ไขไฟล์ appsettings.json

ลองรันอีกทีก็ยังใช้ได้ปกติ

Securing ASP.NET Core 2.0 Endpoints with JWTs

สร้าง BooksController เปล่าขึ้นมาแล้ว ลบ ValuesController

เมื่อรันจะเข้า https://localhost:44307/api/values แล้ว Error ว่า
This localhost page can’t be found
No webpage was found for the web address: https://localhost:44307/api/values
HTTP ERROR 404

เพราะ ValuesController ลบไปแล้ว

Properties/launchSettings.json
แก้ไขไฟล์ Properties/launchSettings.json

เมื่อรันจะเรียกไปที่ http://localhost:62763/api/books
แต่ Error ว่า
This localhost page can’t be found
No webpage was found for the web address: http://localhost:62763/api/books
Search Google for localhost 62763 api books
HTTP ERROR 404

แก้ไขไฟล์ BooksController.cs
แก้ไขไฟล์ BooksController.cs

บรรทัดที่ 13 : กำหนดให้ต้อง Authorize ถึงจะเข้าใช้งานเมธอด Get ได้
บรรทัดที่ 14 : ประกาศเมธอด Get

เมื่อรันจะเรียกไปที่ http://localhost:62763/api/books
และขึ้น Error ว่า
This page isn’t working
If the problem continues, contact the site owner.
HTTP ERROR 401

ซึ่งถูกแล้ว เพราะที่ BooksController มีการใช้ [HttpGet, Authorize] ทำให้การใช้งานต้องส่ง Token ไปด้วยถึงจะใช้งานได้

Creating JWT on Authentication

แก้ไขไฟล์ TokenController.cs
สร้างและแก้ไขไฟล์ TokenController.cs

ทีนี้ลองใช้ Postman เรียกไปที่ http://localhost:62763/api/token
พร้อมส่งค่าไปดังนี้

{
	"username": "mario", 
	"password": "secret"
}

เลือกเมธอด POST ตั้งค่า Header เป็น Content-Type: application/json (น่าจะ default อยู่แล้ว)

Body ใส่ค่า json ของ username และ password ลงไป

จะได้ค่าคืนมาเป็นแบบข้างล่างนี้

{
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJNYXJpbyBSb3NzaSIsImVtYWlsIjoibWFyaW8ucm9zc2lAZG9tYWluLmNvbSIsImJpcnRoZGF0ZSI6IjI1MjYtMDktMjMiLCJqdGkiOiI5NGE1YWY5NC0zYjVkLTQ3MzQtYTUxZC1jYjNjNThhOGYwZWMiLCJleHAiOjE1MzU1MzY3NDYsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NDQzMDcvIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo0NDMwNy8ifQ.itv-IFTvbuA0HkVFvzNlN6FmicMfdzDEdAJhPqyVrGM"
}

Note: ใน Postman ตรง Test Results มีขึ้นแจ้งว่า There was an error in evaluating the test script: SyntaxError: Unexpected token : ไม่ต้องตกใจ ตัวอย่างก็ขึ้น 555

หรือจะใช้คำสั่งแทน Postman เช่น

curl -X POST -H 'Content-Type: application/json' \
  -d '{"username": "mario", "password": "secret"}' \
  0:5000/api/token

แต่อันนี้ยังไม่ได้ลอง (แค่เอาไว้เปรียบเทียบ)

โดยค่าของ token ที่ได้กลับมาจะมี 3 ส่วนคือ Header, Payload และ Signature แต่ละส่วนแบ่งด้วยจุด

จากนั้นนำค่า token ที่ได้มาไปเรียกใช้งาน http://localhost:62763/api/books

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJNYXJpbyBSb3NzaSIsImVtYWlsIjoibWFyaW8ucm9zc2lAZG9tYWluLmNvbSIsImJpcnRoZGF0ZSI6IjI1MjYtMDktMjMiLCJqdGkiOiI5NGE1YWY5NC0zYjVkLTQ3MzQtYTUxZC1jYjNjNThhOGYwZWMiLCJleHAiOjE1MzU1MzY3NDYsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NDQzMDcvIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo0NDMwNy8ifQ.itv-IFTvbuA0HkVFvzNlN6FmicMfdzDEdAJhPqyVrGM

โดยสามารถส่งจาก Postman ได้ 2 แบบ คือ
1. ส่ง Token ที่แทบ Header

ส่งด้วยเมธอด Get

ไปที่ Headers ยกเลิก Content-Type แล้วเพิ่ม Authorization และกำหนดค่าเป็น Bearer ตามด้วย ค่าของ Token

2. ส่ง Token ที่แทบ Authorization

ส่งด้วยเมธอด Get

ยกเลิกค่าใน Headers ทั้งหมด
ไปที่ Authorization เลือก Type เป็น Bearer Token แล้วใส่ค่า Token

จะได้ข้อมูลส่งกลับดังนี้

[
    {
        "author": "Ray Bradbury",
        "title": "Fahrenheit 451",
        "ageRestriction": false
    },
    {
        "author": "Gabriel García Márquez",
        "title": "One Hundred years of Solitude",
        "ageRestriction": false
    },
    {
        "author": "George Orwell",
        "title": "1984",
        "ageRestriction": false
    },
    {
        "author": "Anais Nin",
        "title": "Delta of Venus",
        "ageRestriction": true
    }
]

การส่งโดยใช้คำสั่งทำได้ดังนี้

curl -H 'Authorization: Bearer '$JWT 0:5000/api/books

โดย $JWT คือ Token ที่ได้มา

 

Handling JWT Claims on ASP.NET Core 2.0

Claims could be, for example, user’s e-mail, gender, role, city, or any other information useful to discriminate users while accessing to resources. We can add claims in a JWT so that they will be available while checking authorization to access a resource.

Enabling Cross-Origin Requests (CORS) in ASP.NET Core 2.0

Aside: Securing ASP.NET Core 2.0 with Auth0

 

Link

 

Link – Roles