เมื่อ Token ตัวร้ายหมดอายุ ตอนที่ 1 (Refresh Token in Android with Retrofit Part 1)

Taweewong Tocharoen
Nextzy
Published in
2 min readMar 4, 2020

--

กาลครั้งหนึ่งนานมาแล้ว นานมากจน token หมดอายุไปซะแล้ว.. แต่หากคุณคือ developer คนนึงที่เคยสัมผัสการทำ Authentication แบบ Token-based มาคงจะรู้ดีว่าเมื่อ Token หมดอายุ สิ่งที่คุณอาจจะต้องทำก็คือ Refresh Token นั่นเอง

ในบทความนี้ผมจะมาแชร์เรื่องการทำ Refresh Token ใน Android สำหรับผู้ที่ใช้ Retrofit และ OkHttp ครับ โดยสิ่งที่ผมจะใช้เป็นหลักในบทความนี้ก็คือ Interceptor ครับ

Interceptor แบบขอสั้นๆ

ใครที่รู้จักอยู่แล้วก็สามารถข้ามไปหัวข้อต่อไปได้เลยนะครับ แต่หากคุณยังไม่เคยใช้ล่ะก็ผมจะพาไปแนะนำให้รู้จักแบบคร่าวๆ (มากๆ)

Interceptor คือสิ่งที่จะมาคั่นกลางระหว่างคุณที่ยิงสั่งยิง Service เพื่อทำอะไรสักอย่างก่อนที่จะยิง Service ออกไปจริงๆ

ผมจะขอยกตัวอย่างเหตุการณ์ประกอบนะครับ ปกติเวลาเรายิง Service ด้วย Retrofit จะเป็น code หน้าตาประมาณนี้

หลังจากวินาทีที่คุณเรียกคำสั่ง enqueue() คุณผู้อ่านอาจจะคิดว่าเราไม่สามารถแตะต้องอะไรมันได้เลยจนกว่า Response จะกลับมา แต่จริงๆ แล้ว เราสามารถเอา Interceptor ไปคั่นไว้ก่อนได้นะ อาจจะเช็ค Header ของ Request ก่อน ถ้าขาดอะไรใส่เพิ่มได้เลย หรือเป็นขากลับตอนที่ได้ Response มาก็ได้ อาจจะเช็ค Response ก่อน เพื่อเอามาดัดแปลงก่อนจะส่งไปที่ Callback ตรงที่เราสั่ง enqueue() นั่นแหละ

ลองดูรูปประกอบนะครับ

Why Interceptor?

คุณผู้อ่านบางคนอาจจะสงสัยว่าเราจะใช้ Interceptor ทำ Refresh Token ทำไมล่ะ ในเมื่อเราก็ยิง Service ปกติ แล้วรอ response กลับมา จากนั้นดัก 401 แล้วค่อยทำ Refresh Token ตรงนั้นเลยก็ได้นี่นา แบบเนี้ย

งั้นลองนึกภาพว่าภายในแอปของเรามี Service อยู่สัก 20 Service หรือมากกว่านั้นสิ เราจะมี code ที่ดัก 401 และทำ Refresh Token อยู่ในทุก Callback ของ Service เลยนะ แบบนั้นคงไม่ดีเท่าไหร่ แต่ถ้าเราใช้ Interceptor เราแค่ยัดมันไว้ใน Retrofit ที่เราใช้ยิง Service เลย จบ~

Let’s Create the Interceptor for Token Expired

การสร้าง Interceptor นั้นทำได้โดยการสร้าง class ที่ implement Interceptor แล้วก็ override method intercept(...)

แล้วตอนที่ interceptor ถูกเรียกขึ้นมา request ที่เราส่ง และ response ที่เราได้ จะผ่านใน method intercept(...) เสมอ

อย่างที่เข้าใจว่า interceptor อยู่ตรงกลางระหว่าง Application และ Network ทำให้ request และ response ทั้งขาไปขากลับจะผ่านเจ้านี่เสมอ

ขาไปนั้นเราสามารถเรียก request ของเรามาดูก่อนได้จนกว่าเราจะสั่ง chain.proceed() ถ้าเรียกคำสั่งนี้เมื่อไหร่คือเราบอกให้ผ่าน interceptor ตัวนี้ไปได้

แต่ว่าพอ response กลับมาผ่าน interceptor ตัวนี้อีกครั้งมันจะกลับมายังจุดที่เราเรียก chain.proceed() เอาไว้

และสุดท้ายคือเราต้อง return Response กลับไปให้ฝั่ง Application ด้วย

วางแผนกันก่อนสักนิด สิ่งที่เราต้องการทำหลังจาก response กลับมาก็คือ ตรวจสอบก่อนว่าเป็น 401 Token Expired หรือไม่ ถ้าใช่เราจะเรียก service Refresh Token แล้วพอ Refresh สำเร็จเราจะยิง Service เดิมซ้ำอีกครั้ง แต่ถ้ายิงครั้งแรกแล้ว Token ไม่ Expired เราจะส่ง response เดิมกลับไปให้ Application เลย ก็จะได้ code คร่าวๆหน้าตาประมาณนี้

จะเห็นว่าถ้า response เป็น 401 และเราสามารถ Refresh Token และยิง service ใหม่ได้สำเร็จเราจะส่ง response ใหม่กลับไปให้ Application แต่ถ้าไม่เป็นเช่นนั้นเราก็จะส่ง response ดั้งเดิมกลับไปนั่นเอง

นี่เป็นเพียงตัวอย่างและแนวทางคร่าวๆ ในการทำ Refresh Token ใน Interceptor นะครับ ตอนที่ทำจริงๆ คงจะต้องมีการปรับเปลี่ยนให้เข้ากับสถานการณ์

Add Your Interceptor to Retrofit

ขั้นตอนสุดท้ายคือการเพิ่ม Interceptor เข้าไปใน Retrofit ของเรา และทุกครั้งที่เราใช้ Retrofit ตัวนี้ในการยิง Service มันจะผ่าน Interceptor ของเราทุกครั้ง

Conclusion

ในการเขียนเงื่อนไขเพื่อทำ refresh token เราสามารถดักใน Callback ของ Retrofit ได้อยู่แล้ว เพียงแต่ว่าการทำแบบนั้นจะทำให้เรามี code ที่ซ้ำกันในหลายๆ ที่ เราจึงใช้ Interceptor เข้ามาช่วยเพื่อลด code ที่ซ้ำกัน และลดความซับซ้อนของ code เวลาที่เราเรียก service จาก network ด้วยครับ

สำหรับบทความนี้จะมีตอนที่สองด้วยนะครับ สำหรับคนที่สงสัยว่าถ้าเราเขียน Interceptor แบบนี้แล้วเราจะเขียน Test ยังไงนะ ตามลิงค์ด้านล่างไปเลยครับ

--

--