มาปกป้อง Microservice ด้วย OAuth2 ใน Spring Boot

Phayao Boonon
4 min readSep 10, 2018

จากบทความสร้าง CRUD ​Microservice ด้วย Spring Boot นั้นป้องกัน Microservice ด้วย Basic Authorization นั้นคือใช้ Username และ Password ธรรมา ซึ่งเป็นระดับความปลอดถัยที่ไม่ค่อยดีนักสำหรับ Microservice ดังนั้นบทความนี้ก็จะเพิ่มความปลอดภัยมาอีกขั้นด้วยการใช้ OAuth2 กับ Spring Boot Service

OAuth2 คืออะไร

เป็นโปรโตคอลมาตรฐานสำหรับ Authorization ซึ่ง OAuth2 เป็นเวอร์ชันต่อของโปรโตคอลมาตรฐาน OAuth ที่สร้างขึ้นมาตั้งแต่ปี 2006 โดยที่ OAuth2 จะโฟกัสที่ความง่ายของการพัฒนาฝั่ง Client ขณะที่มีขั้นตอนการ Authorization เฉพาะสำหรับแอพพลิเคชัน Web, Desktop, Mobile และ IOT สามารถอ้างอิงจากสเปก RFC 6749

OAuth2 กำหนดให้มี 4 Role ดังนี้

  • Resource Owner — User ที่ต้องการเข้าถึง resource ของ API
  • Resource Server — ที่เก็บ resource ของ API, ที่เราต้องรักษาความปลอดถัย
  • Client — เป็น application ที่ใช้งาน resource ของ API
  • Authorization Server — บริการอนุญาตให้เข้าถึง resource API ได้

API = Microservice API

ขั้นตอน OAuth2

ลำดับขั้นตอนของ OAuth authentication แบบง่าย ดังนี้

  1. Client ร้องขอไปยัง Resource Owner ว่าต้องการเข้าถึง Resource Server
  2. เมื่อ Resource Ownerให้อนุญาต, Client จะได้รับ authorization grant ของ Resource Owner
  3. Client ส่ง authorization grant ของ Resource Owner และ client credentials ไปยัง Autorization Server
  4. ถ้า authentication สำเร็จ, Authorization Server จะส่ง access token กลับมา
  5. Client เรียกไปหา Resource Server ด้วย access token สำหรับ authentication
  6. ถ้า authentication สำเร็จ Resource Server จะ response เป็นข้อมูลที่ Client ต้องการ

เพิ่ม OAuth2

จาก demo project ของ CRUD Microservice เราก็มาเพิ่ม Maven dependency ของ OAuth2 ใน pom.xml ดังนี้

<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

ซึ่งใช้ spring-security-oauth2-autoconfigure เพื่อ config service ให้รองรับ OAuth2

แต่ในขึ้นตอนนี้จะเพิ่ม OAuth2 เข้าไปใน Application ที่เรามีอยู่แล้วเพื่อแสดงให้เห็นว่า Microservice เราได้รับการป้องกันเพิ่มเติม

เพิ่ม 2 annotation @EnableResourceServer และ @EnableAuthorizationServer ไปที่ entry point ของ Application ซึ่งเป็นการบอกว่าให้คลาสนี้เป็นทั้ง Resource Server และ Authorization Server

  • @EnableResourceServer — annotation ที่กำหนดให้คลาสเป็น Resource Server ด้วยการเปิดให้ Spring Security กรอง authentication request ด้วบ OAuth2 token เท่านั้น
  • @EnableAuthorizationServer — annotation ที่กำหนดให้คลาสเป็น Authorization Server ด้วย AuthorizationEndpoint และ TokenEndpoint ใน application context ซึ่งจะต้องเป็น Dispatcher Servlet context

เพิ่ม config ใน application.yml เพื่อตั้งค่าของ ​Authorization Server ด้วย client-id client-secret authorized-grant-types และ scope

ทดสอบ OAuth2 เบื้องต้น

หลังจากที่เราได้เพิ่มค่าต่างๆ เพื่อทำให้ Microservice ของเราปกป้องด้วย OAuth2 ต่อไปก็ลองรัน application ด้วย IntelliJ หรือ mvn spring-boot:run

  1. ทดลอง request ไปที่ Authorization Server เพื่อรับ access token ด้วย POST method พร้อมกับ
  • Authentication เป็นแบบ Basic Auth username = client-id, password = client-secret
  • Body เป็น form-data (grant_type = password, username = john, password = P@ssw0rd)

ก็จะได้ response เป็น access_token, token_type, refresh_token, expire_id และ scope ซึ่งเราจะใช้ access_token ในการเรียกไปยัง Resource Server หรือ API

2. ทดลอง request ไปที่ API หรือ Resource Server วิธีการเดิม (Basic Auth) ด้วย Username และ Password จะเห็นได้ว่าเราไม่สามารถเข้าถึง API ของเราได้แล้ว เนื่องจากว่าเราเปิดการใช้งานให้ application context ต้องเข้าถึงได้ด้วย OAuth2 เท่านั้น

3. ทดลอง request ไปที่ Resource Server หรือ API ด้วยการใช้ access token ที่ได้จากตอนเราที่ request ไปยัง Authentication Server ด้วยการเลือก Authorization type เป็น Bearer Token และใส่ Token เป็น access token จะเห็นได้ว่าเราสามารถ POST request ไปที่ Microservice API ได้แล้ว

แยก Authorization Server

แต่วิธีการแบบนี้เราใช้ Server (Microservice) เดียวกันเป็นทั้ง Resource Server และ Authorization Server ทำให้มีข้อจำกัด เพราะเราจะต้อง reqeust access token ทุกครั้งที่ต้องการเข้าถึง Resource Server ซึ่งต่อไปเราจะแยก Authorization Server ออกจาก Microservice

สร้าง Spring Boot project ใหม่สำหรับเป็น Authentication Server และแน่ใจว่ามี dependency spring-security-oauth2-autoconfigure ใน pom.xml และย้าย @EnableAuthorizationServer มายัง project นี้

และย้ายส่วนของ client security มาใส่ใน application config ของ Authorization Server โดยกำหนด port ให้แตกต่างจาก Resource Server เป็น port: 9000

แค่นี้เอง!!! ใน Authorization Server จะไม่มี implementation เพิ่มเติมส่วนใหญ่จะใช้ default implementation ของ Spring Boot Security

แก้ไข Resource Server

หลังจากที่แยก Authorization Server ออกไปจาก demo project แล้วก็ต้อง refactor ในกับ demo project ดังนี้

เอา @EnableAuthorizationServer ออกจาก DemoApplication

เอาส่วนของ security.oauth2.client และเพิ่ม security.oauth2.resource เพื่อกำหนด path ที่ให้ Resource Server ตรวจสอบ token ที่กับ Authorization Server http://localhost:9000/oauth/check_token/ ว่าถูกต้องไหม เพราะใน Resource Server ไม่ได้เก็บข้อมูลของ Client ไว้

ทดสอบ OAuth2 ขั้นสุดท้าย

หลังจากที่ได้แยก Authorization Server ออกจาก demo application แล้วและให้เป็นเพียง Resource Server อย่างเดียว ก็มาทดสอบว่าทำงานได้ไหม

รัน Authorization Server จะเห็นได้ว่ารันบน port 9000 โดยจะใช้ 2 endpoint คือ

http://localhost:9000/oauth/token
http://localhost:9000/oauth/check_token/

แต่จะ Client จะ request มาที่ /oauth/token และ Resource Server จะ request มาที่ /oauth/check_token/ (จะต้องมี / ด้วย ถ้าไม่มีจะได้ 403 error)

รัน ​Resource Server จะเห็นได้ว่ารันบน port 8080 ด้วย path /api

  1. ทดลอง request ไปที่ Authorization Server เพื่อรับ access token ด้วย POST method เหมือนกับข้างต้น แต่เปลี่ยนจาก port 8080 เป็น 9000 จะได้ response เป็น access_token, token_type, refresh_token, expire_id และ scope ซึ่งเราจะใช้ access_token ในการเรียกไปยัง Resource Server

2. ทดลอง request ไปที่ Resource Server port 8080 เหมือนเดิม ด้วย access token ที่ได้จากตอนเราที่ request ไปยัง Authentication Server ด้วยการเลือก Authorization type เป็น Bearer Token และใส่ Token เป็น access token จะเห็นได้ว่าเราสามารถ POST request ไปที่ Microservice ได้ เหมือนกับที่มี Authorizatoin Server และ Resource Server อยู่บน Server (Microservice) เดียวกัน

สรุป

จากการเพิ่มการป้องกัน Microservice ใน Spring Boot ด้วย OAuth2 นั้นเป็นการเพิ่มความปลอดภัยเพิ่มเติมที่มากกว่าการใช้ Basice Auth ธรรมดา ด้วยการใช้ Token request มาหา Microservice แต่อาจจะเพิ่ม Authorizatoin Server ถ้าเราต้องการแยกกันกับ Resource Server เพื่อทำให้ระบบโดยรวมของเรายืดหยุ่นและสามารถ reuse ใช้งาน Token ได้ ถ้ายังไม่หมดอายุ แต่ก็ยังมีการตรวจสอง Token จาก Resource Server ไปยัง Authorization Server ที่มีข้อมูลของ Client

--

--

Phayao Boonon

Software Engineer 👨🏻‍💻 Stay Hungry Stay Foolish