วันพุธที่ 20 กรกฎาคม พ.ศ. 2554

taglib Authorization by spring security on spring3 richfaces4 jsf2

ในส่วน authorization นี้ พูดในเรื่องของ tag ที่ใช้ในการกำหนดสิทธิ บนหน้า web เป็นหลัก โดยต่อยอดมาจากบนความก่อนหน้าในเรื่อง authentication

authentication by spring security on spring3 richfaces4 jsf2

สิ่งสำคัญในของหน้าที่ authorization คือ การให้สิทธิ ที่ไม่เท่าเทียมกันของ ผู้เข้ามาใช้ระบบ ซึ่ง บางคนสามารถทำการสร้างลบข้อมูลได้ ส่วนบางคน ควรจะมีหน้าที่ดู เพื่อรับข้อมูลอย่างเดียว เป็นต้น

ในที่นี้ ต่อจากหน้า login.xhtml ในคราวที่แล้ว ให้เราสร้างหน้า home.xhtml ขึ้นมา

== home.xhtml ==
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:a4j="http://richfaces.org/a4j"
      xmlns:rich="http://richfaces.org/rich"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:sec="http://www.springframework.org/security/facelets/tags">
   
   status : 
   <sec:isAnonymous > anonymous user -_- </sec:isAnonymous > 
   <sec:isAuthenticated > authenticate user ^_^ </sec:isAuthenticated > 
   
   role : 
   <sec:ifNotGranted roles="ROLE_ADMIN">not admin</sec:ifNotGranted >
   <sec:ifAnyGranted roles="ROLE_ADMIN">admin</sec:ifAnyGranted >
   
   <sec:ifAllGranted roles="ROLE_ADMIN, ROLE_USER">both role (user, admin)</sec:ifAllGranted >
   
</html>

ในส่วนนี้เป็นตัวอย่างง่าย ๆ คือ เราต้องประกาศ

xmlns:sec="http://www.springframework.org/security/facelets/tags"

ขึ้นมาก่อน เพื่อใช้ tag ในการทำเรื่อง authorization ได้
หลังจากนั้น เราก็ใช้งาน หลักการง่าย ๆ คือ ถ้า roles ที่กำหนดไว้ ตรงกับ ชื่อ sec:? นั้น ก็จะทำการแสดงข้อความที่อยู่ด้านใน tag sec:? นั้นๆ ได้ โดยในที่นี้ ลองดูมีอยู่ 5 tag ได้แก่


<sec:isAnonymous />

ใช้เพื่อถามว่าเป็น บุคคลทั่วไป หรือเปล่า

<sec:isAuthenticated />

ใช้เพื่อถามว่าเป็น บุคคลในระบบ หรือเปล่า

<sec:ifAllGranted roles="?" />

ใช้เพื่อถามว่าเป็น บุคคลที่อยู่ในตำแหน่งต่าง ๆ เหล่านี้ทั้งหมดหรือเปล่า

<sec:ifNotGranted roles="?" />

ใช้เพื่อถามว่าเป็น บุคคลที่ไม่ได้อยู่ในตำแหน่งต่าง ๆ เหล่านี้ทั้งหมดหรือเปล่า

<sec:ifAnyGranted roles="?" />

ใช้เพื่อถามว่าเป็น บุคคลที่อยู่ในตำแหน่งใดตำแหน่งหนึ่ง ในที่นี้หรือเปล่า

authentication by spring security on spring3 richfaces4 jsf2

authentication กล่าวเกริ่นแบบไม่แปลให้งงเล่นได้ว่า ในส่วนของ web หรือ application ที่เราได้สร้างขึ้นมานั้น ส่วนที่ทำให้ระบบเราปลอดภัย และจำกัดผู้ไม่เกี่ยวข้องในการใช้งานอันดับแรกเลยก็คนเป็นเรื่องของการแสดงตัวตนผู้ใช้ที่เข้ามาในระบบนั่นเอง

ในส่วนนี้จะมี library ที่จำเป็น และ ใช้งานได้ง่ายดังนี้ โดยจะขอยกยอดมาจาก เนื้อเรื่อง spring framework บทก่อนๆ นะครับ ไม่ค่อยได้เริ่มอะไรใหม่เพราะยาวแล้วจะไม่อยากอ่านกัน
JSF 2.0 and Spring Framework annotation example

ขอแสดงเป็น xml maven แล้วกันนะครับ เพื่อความสะดวก โดยเพิ่มส่วนดังต่อไปนี้เข้าไป (ถ้ามีแล้วก็ไม่ต้องเพิ่มซ้ำนะ)
== pom.xml ==

 org.springframework.security
 spring-security-core
 3.0.5.RELEASE


 org.springframework.security
 spring-security-web
 3.0.5.RELEASE



 org.springframework.security
 spring-security-config
 3.0.5.RELEASE


 org.springframework.security
 spring-security-taglibs
 3.0.5.RELEASE


 org.springframework.security
 taglib-core
 0.4


 org.springframework.security
 facelets-taglib-jsf20-spring-3
 0.5


และเพิ่มในส่วนของ repository เข้าไป เพราะ jar file บางตัว ไม่ได้อยู่ center


 org.springframework.security.taglibs.facelets
 Repository for library Library[spring-security-facelets-taglib-googlecode]
 http://spring-security-facelets-taglib.googlecode.com/svn/repo/


หลังจากนั้น ก็เพิ่ม code ใน file web.xml เพื่อให้ spring security เริ่มทำงานได้

== web.xml ==

 springSecurityFilterChain
 org.springframework.web.filter.DelegatingFilterProxy


 springSecurityFilterChain
 /*


หลังจากนั้น ก็ทำการ setup บน application context file แต่ในที่นี้ เราแยกออกมาเป็นอีก file โดย file applicationContext.xml เราเพิ่ม code ไปว่า

== applicationContext.xml ==
<import resource="/security.xml"  />

== security.xml ==



    
    
        <intercept-url pattern="/login.xhtml" filters="none" />
        <intercept-url pattern="/images/**" filters="none" />
        <intercept-url pattern="/javascript/**" filters="none" />
        <intercept-url pattern="/css/**" filters="none" />
        <intercept-url pattern="/javax.faces.resource/**" filters="none" />
        <intercept-url pattern="/rfRes/**" filters="none" />
        <intercept-url pattern="/**"  access="ROLE_USER" />
        <form-login login-page="/login.xhtml" default-target-url='/home.xhtml'
            always-use-default-target='true' />
        <logout/>
    
    
    

    
        
            
                
                
            
        
    


ในครั้งนี้เราเปลี่ยน tag beans ที่เคยเป็น default มาเป็น tag security เป็น default แทน เพิ่มทำให้ tag ดูง่ายขึ้น แต่ tag beans เปลี่ยนไปนิดหน่อย
เอาเป็นว่า ในที่นี้เรา สร้าง user มาสองคน ชื่อว่า nai_a กับ nai_b ใน tag authentication-manager
ในส่วน tag http เอาไว้กำหนด หน้าที่ต้องการให้สิทธิใดเข้าถึง รายละเอียดคงต้องหาอ่านกันต่อไปนะ

หลังจากนั้น เราก็มาสร้างหน้า login กันดีกว่า เพื่อให้ครบวงจรซะที

== login.xhtml ==
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:a4j="http://richfaces.org/a4j"
      xmlns:rich="http://richfaces.org/rich"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:p="http://primefaces.prime.com.tr/ui">

    <f:view locale="#{localizationBean.locale}">

        <h:head>
            <title>Project Tracking.</title>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
            <link type="text/css" rel="stylesheet" href="css/default.css" />
        </h:head>

        <h:body onload='document.f.j_username.focus();'>

            <center>
                <p:panel header="Login with Username and Password" style="width:400px;">
                    <form name='f' action='j_spring_security_check' method='POST'>
                        <table>
                            <tr><td colspan="2">  </td></tr>
                            <tr><td>User:</td><td><input type='text' name='j_username' value=''/></td></tr>
                            <tr><td>Password:</td><td><input type='password' name='j_password'/></td></tr>
                            <tr><td colspan="2">  </td></tr>
                            <tr align="center">
                                <td colspan="2">
                                    <input name="submit" type="submit"/> 
                                    <input name="reset" type="reset"/>
                                </td>
                            </tr>
                        </table>
                    </form>
                </p:panel>
            </center>
            <br/>
            ROLE_ADMIN nai_a : jimispassword<br/>
            ROLE_USER nai_b : bobspassword<br/>
        </h:body>
    </f:view>
</html>

ในส่วนนี้จะเป็น หน้า login ที่ทำการกรอก user, password ธรรมดา แต่มีการใช้ tag primefaces เข้ามาช่วย ก็ไม่ต้องสนใจ ในที่นี้ แค่ต้องการนำเอา user, password ส่งไปยัง j_spring_security_check เท่านั้น ถ้าถูกต้องก็จะเข้าไปยังหน้า home.xhtml ดังที่เราได้กำหนดไว้
และถ้า กรอกข้อมูลผิด ก็จะยังอยู่ในหน้า login อีกครั้ง เนื่องจากหน้า login ถูกกำหนดเป็นหน้า default กรณียังไม่ทำการ login ที่ file security.xml