หลังจากพึ่งพา Security module มานานและขัดใจกับ @With(Secure.class) ที่ method ทั้งหมดจะ access ได้ต้อง authen ก่อนแต่บาง method ไม่ต้องการอย่างนั้นเลยต้องสร้าง class แยก วันนี้ลองขุดๆ code security module ดูถึงรู้ว่าจริงๆ แล้ว @With มีหน้าที่อะไร และ @Before ทำอะไรได้ และ @Check จริงๆ แล้วมันทำงานยังไง
@With ใช้สำหรับรวม method ของ Class เข้าด้วยกันทำให้ annotation ต่างๆ เช่น @Before @After… มองเห็นข้าม class ที่ถูกประกาศไว้ เช่น
class A extends Controller { @Before public static void setup() { .. Do something .. } @After public static void tearDown() { .. Do something .. } } @With(A.class) class B extends Controller { public static void show() { render(); } }
จาก code ด้านบนเมื่อเรียกมาที่หน้า B.show จะมีการเรียก setup และ tearDown ก่อนและหลังจากที่ method show ทำงานและจาก code ด้านบน @Before คือ annotation ที่ใช้สำหรับบอกว่า method ไหนจะถูกเรียกก่อนที่ method อื่นจะทำงาน ส่วน @After ก็ทำงานตรงข้ามคือหลังจาก method ทำงานเสร็จแล้ว สามารถกำหนดได้ว่าจะทำงานที่ method ไหนบ้าง และกำหนด priority ได้ว่าอะไรทำก่อนหลัง
คราวนี้มาดูว่า Check ทำงานยังไงบ้างโดยมาดู code ที่ class Secure ใน Security module
@Before(unless={"login", "authenticate", "logout"}) static void checkAccess() throws Throwable { // Authent if(!session.contains("username")) { flash.put("url", "GET".equals(request.method) ? request.url : "/"); // seems a good default login(); } // Checks Check check = getActionAnnotation(Check.class); if(check != null) { check(check); } check = getControllerInheritedAnnotation(Check.class); if(check != null) { check(check); } } private static void check(Check check) throws Throwable { for(String profile : check.value()) { boolean hasProfile = (Boolean)Security.invoke("check", profile); if(!hasProfile) { Security.invoke("onCheckFailed", profile); } } }
จากด้านบนจะเห็นว่า ก่อนที่ method ไหนจะทำงานยกเว้น login, authenticate, logout จะต้องเรียก checkAccess ก่อน ในนั้นก็จะดูว่า login แล้วหรือยังจากนั้นถึงดึงค่า annotation ออกมาเพื่อ check ว่าสิทธิ์ถึงหรือป่าวผ่าน Security class เอาหละเมื่อรู้แล้วว่าปัญหามันคือการบังคับว่าต้อง login ก่อนในนี้และ annotation แต่ละตัวทำงานยังไงแล้ว ก็สามารถสร้างตัวทดแทนตามต้องการได้หละ โดยแค่เอา check session ออกก็เสร็จ แต่ดู code ตรงนี้ทำให้รู้ว่า annotation ต่างๆ ใน Play เอามาเล่นได้อีก เพราะนอกจาก @With @Before @After แล้วใน play.mvc ก็ยังมี annotation อีกสามตัวให้เล่น ไว้ได้เล่นแล้วจะมาเขียนอีกที