<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-193  評(píng)論-715  文章-1  trackbacks-0
    在昨天的文章《BlazeDS結(jié)合Tomcat進(jìn)行權(quán)限控制》中,講述了BlazeDS如何在Tomcat環(huán)境下進(jìn)行權(quán)限控制,但是我們不難發(fā)現(xiàn)有很多缺點(diǎn),甚至有一些都是致命的,比如不能跨平臺(tái)(中間件),甚至不能跨版本,還有用戶名角色等配置不能自定義配置在RDBMS,文件或其它地方等。所以今天我要分享給大家如何擺脫這些限制,避免這些不利因素。

    所幸的是,BlazeDS的設(shè)計(jì)者們已經(jīng)為我們想到了這些,我們只需要采用自定義認(rèn)證的方式即可,具體實(shí)現(xiàn)時(shí),需要實(shí)現(xiàn)flex.messaging.security.LoginCommand這個(gè)接口。我們不妨先來(lái)看看這個(gè)接口的定義(直接上代碼了):
    package flex.messaging.security;

    import javax.servlet.ServletConfig;

    import java.security.Principal;
    import java.util.List;

    /**
     * The class name of the implementation of this interface is configured in the
     * gateway configuration's security section and is instantiated using reflection
     * on servlet initialization.
     
    */

    public interface LoginCommand
    {
        
    /**
         * Called to initialize a login command prior to authentication/authorization requests.
         * 
         * 
    @param config The servlet configuration for MessageBrokerServlet.  
         
    */

        
    void start(ServletConfig config);

        
    /**
         * Called to free up resources used by the login command.
         
    */

        
    void stop();

        
    /**
         * The gateway calls this method to perform programmatic, custom authentication.
         * <p>
         * The credentials are passed as a Map to allow for extra properties to be
         * passed in the future. For now, only a "password" property is sent.
         * </p>
         *
         * 
    @param username    The principal being authenticated
         * 
    @param credentials A map, typically with string keys and values - holds, for example, a password
         * 
    @return principal for the authenticated user when authentication is successful; null otherwise 
         
    */

        Principal doAuthentication(String username, Object credentials);

        
    /**
         * The gateway calls this method to perform programmatic authorization.
         * <p>
         * A typical implementation would simply iterate over the supplied roles and
         * check that at least one of the roles returned true from a call to
         * HttpServletRequest.isUserInRole(String role).
         * </p>
         *
         * 
    @param principal The principal being checked for authorization
         * 
    @param roles    A List of role names to check, all members should be strings
         * 
    @return true if the principal is authorized given the list of roles
         
    */

        
    boolean doAuthorization(Principal principal, List roles);

        
    /**
         * Attempts to log a user out from their session.
         *
         * NOTE: May not be possible on all application servers.
         * 
    @param principal The principal to logout.
         * 
    @return true when logout is successful
         
    */

        
    boolean logout(Principal principal);
    }

    最主要的3個(gè)方法:doAuthentication()用來(lái)認(rèn)證,doAuthorization()用來(lái)進(jìn)行授權(quán),logout()用來(lái)執(zhí)行登出時(shí)的動(dòng)作,主要是釋放Principal,關(guān)于Principal的概念,直接來(lái)自于Java,如需進(jìn)一步了解,也可以參考JAAS的相關(guān)知識(shí),我在之前的學(xué)習(xí)筆記《JAAS Study Note 》中也簡(jiǎn)單的提及過(guò),在此就不再多講了,廢話不多說(shuō)了,直接上步驟了,這應(yīng)該是大家喜歡的方式:

    1,實(shí)現(xiàn)一個(gè)自定義的Principal:
    package com.robin.common.security;

    import java.security.Principal;
    import java.util.List;

    public class UserPrincipal implements Principal, java.io.Serializable {

        
    private String name;
        
    private List<String> subjects;

        
    /**
         * Create a SamplePrincipal with a Sample username.
         * 
         * <p>
         * 
         * 
    @param name
         *            the Sample username for this user.
         * 
         * 
    @exception NullPointerException
         *                if the <code>name</code> is <code>null</code>.
         
    */

        
    public UserPrincipal(String name) {
            
    if (name == null)
                
    throw new NullPointerException("illegal null input");

            
    this.name = name;
        }


        
    public List<String> getSubjects() {
            
    return subjects;
        }


        
    public void setSubjects(List<String> subjects) {
            
    this.subjects = subjects;
        }


        
    public String getName() {
            
    return name;
        }


        
    /**
         * Return a string representation of this <code>SamplePrincipal</code>.
         * 
         * <p>
         * 
         * 
    @return a string representation of this <code>SamplePrincipal</code>.
         
    */

        
    public String toString() {
            
    return ("Principal's username:  " + name);
        }


        
    /**
         * Compares the specified Object with this <code>SamplePrincipal</code> for
         * equality. Returns true if the given object is also a
         * <code>SamplePrincipal</code> and the two SamplePrincipals have the same
         * username.
         * 
         * <p>
         * 
         * 
    @param o
         *            Object to be compared for equality with this
         *            <code>SamplePrincipal</code>.
         * 
         * 
    @return true if the specified Object is equal equal to this
         *         <code>SamplePrincipal</code>.
         
    */

        
    public boolean equals(Object o) {
            
    if (o == null)
                
    return false;

            
    if (this == o)
                
    return true;

            
    if (!(o instanceof UserPrincipal))
                
    return false;
            UserPrincipal that 
    = (UserPrincipal) o;

            
    if (this.getName().equals(that.getName()))
                
    return true;
            
    return false;
        }


        
    /**
         * Return a hash code for this <code>SamplePrincipal</code>.
         * 
         * <p>
         * 
         * 
    @return a hash code for this <code>SamplePrincipal</code>.
         
    */

        
    public int hashCode() {
            
    return name.hashCode();
        }

    }


    2,實(shí)現(xiàn)自定義的LoginCommand:
    package com.robin.common.security;

    import java.security.Principal;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;

    import javax.servlet.ServletConfig;

    import flex.messaging.io.MessageIOConstants;
    import flex.messaging.security.LoginCommand;

    public class RdbmsLoginCommand implements LoginCommand {

        
    public Principal doAuthentication(String username, Object credentials) {
            String password 
    = extractPassword(credentials);
            System.out.println(
    "###Username:"+username+",Password:"+password+"###");
            
    //TODO: use this user name and password to validate from RDBMS.
            
    //And then, query user's roles and set to principle.
            if(true){
                UserPrincipal principal 
    = new UserPrincipal(username);
                List
    <String> subjects = new ArrayList<String>();
                subjects.add(
    "ROLE_AD");
                
    if(username.equals("admin")){
                    subjects.add(
    "ADMIN");
                }

                principal.setSubjects(subjects);
                
    return principal;
            }
     else{
                
    return null;
            }

        }


        
    public boolean doAuthorization(Principal principal, List roles) {
            System.out.println(principal
    +"##########################");
            UserPrincipal p
    =(UserPrincipal)principal;
            List
    <String> subjects = p.getSubjects();
            
    for (int i = 0; i < subjects.size(); i++{
                String subject
    = subjects.get(i);
                
    for (int j = 0; j < roles.size(); j++{
                    System.out.print(roles.get(j)
    +"$$$");
                    
    if(subject.equals(roles.get(j))){
                        
    return true;
                    }

                }

            }

            
    return false;
        }


        
    public boolean logout(Principal principal) {
            System.out.println(principal
    +"will logout at once.");
            principal 
    = null;
            
    return true;
        }


        
    public void start(ServletConfig arg0) {
            
        }


        
    public void stop() {

        }

        
        
    private String extractPassword(Object credentials)
        
    {
            String password 
    = null;
            
    if (credentials instanceof String)
            
    {
                password 
    = (String)credentials;
            }

            
    else if (credentials instanceof Map)
            
    {
                password 
    = (String)((Map)credentials).get(MessageIOConstants.SECURITY_CREDENTIALS);
            }

            
    return password;
        }


    }

    這些代碼都非常簡(jiǎn)單,我想就不用我再解釋了。

    3,在BlazeDS中配置security-constraint,先配置service-config.xml:
    <security>
            
    <login-command class="com.robin.common.security.RdbmsLoginCommand" server="all"/>
            
    <security-constraint id="administrators">
            
    <auth-method>Custom</auth-method>
                
    <roles>
                    
    <role>ADMIN</role>
                
    </roles>
            
    </security-constraint>
            
    <security-constraint id="users">
                
    <auth-method>Custom</auth-method>
                
    <roles>
                    
    <role>ROLE_AD</role>
                    
    <role>ADMIN</role>
                
    </roles>
            
    </security-constraint>
        
    </security>

    然后在remote-config.xml中配置每個(gè)destination的授權(quán)規(guī)則:
    <destination id="DomainService">
            
    <properties>
                
    <source>com.robin.service.domain.DomainService</source>
                
    <include-methods>
                
    <method name="getAllDomains"/>
                
    <method name="addOrUpdateDomain" security-constraint="administrators"/>
                
    </include-methods>
            
    </properties>
            
    <security>
                
    <security-constraint ref="users"/>
            
    </security>
        
    </destination>

    4,服務(wù)端的配置就大功告成了,現(xiàn)在來(lái)看看客戶端如何實(shí)現(xiàn)登錄:
    <?xml version = "1.0" encoding = "utf-8"?>
    <mx:Module xmlns:fx = "http://ns.adobe.com/mxml/2009" xmlns:s = "library://ns.adobe.com/flex/spark" xmlns:mx = "library://ns.adobe.com/flex/mx" layout = "absolute" width = "100%" height = "100%"
               xmlns:component 
    = "com.robin.common.component.*">
        
        
    <fx:Declarations>
            
    <mx:RemoteObject id = "loginService" destination = "remoting_AMF_SecurityConstraint_Custom" showBusyCursor = "true" fault = "Alert.show(event.fault.faultString, 'Error');"/>
        
    </fx:Declarations>
        
    <fx:Script>
            
    <![CDATA[
                import com.robin.common.events.SwitchModuleEvent;
                import mx.controls.Alert;
                import mx.messaging.ChannelSet;
                import mx.messaging.config.ServerConfig;
                import mx.rpc.AsyncResponder;
                import mx.rpc.AsyncToken;
                import mx.rpc.events.FaultEvent;
                import mx.rpc.events.ResultEvent;

                // Define a ChannelSet object.
                public var cs:ChannelSet;
                // Define an AsyncToken object.
                public var token:AsyncToken;

                // Initialize ChannelSet object based on the
               // destination of the RemoteObject component.
                private function creationCompleteHandler():void {
                    if (cs == null)
                       cs = ServerConfig.getChannelSet(loginService.destination);
                }

                // Login and handle authentication success or failure.
                private function login():void {
                    // Make sure that the user is not already logged in.
                    var user:String = username.text;
                    var pwd:String = password.text;
                    if (user == "" || pwd == "") {
                        Alert.show("User name or password is empty, please check them.", "Info");
                        return;
                    }
                    if (this.parentApplication.cs.authenticated == false) {
                        this.parentApplication.token = this.parentApplication.cs.login(user, pwd);
                        // Add result and fault handlers.
                        this.parentApplication.token.addResponder(new AsyncResponder(LoginResultEvent, LoginFaultEvent));
                    }
                }

                // Handle successful login.
                private function LoginResultEvent(event:ResultEvent, token:Object = null):void {
                    switch (event.result) {
                        case "success":
                            break;
                        default:
                    }
                    var switchEvent:SwitchModuleEvent = new SwitchModuleEvent(SwitchModuleEvent.SWITCH, "");
                    dispatchEvent(switchEvent);
                }

                // Handle login failure.
                private function LoginFaultEvent(event:FaultEvent, token:Object = null):void {
                    trace(event.fault.faultCode);
                    switch (event.fault.faultCode) {
                        case "Client.Authentication":
                        default:
                            Alert.show("Login failure: " + event.fault.faultString);
                    }
                }

            
    ]]>
        
    </fx:Script>
        
    <mx:HBox x="100" y = "100">
            
    <component:RequiredLabel text = "user name:" isRequired = "true"/>
            
    <s:TextInput id = "username" text = "admin"/>
            
    <component:RequiredLabel text = "password:" isRequired = "true"/>
            
    <s:TextInput id = "password" text = "" displayAsPassword = "true"/>
            
    <s:Button label = "Login" click = "login();"/>
        
    </mx:HBox>
        
    <s:Label x="100" y="130" text="Notes: You can use any user to register, and if you wanna access add or update functions, you need to user 'admin' user. "/>

    </mx:Module>

    主要是用ChannelSet.login()方法和logout()方法進(jìn)行登錄與登出,登出的詳細(xì)代碼在此就省略了,有興趣的朋友可以自己試試或者參考Adobe官方的《BlazeDS dev guide》。

    小結(jié)一下:
    1,解決了與Tomcat等中間件綁定的問(wèn)題。
    2,可以將用戶和角色的對(duì)應(yīng)關(guān)系存放在RDBMS中,并可以開發(fā)相應(yīng)功能進(jìn)行動(dòng)態(tài)編輯而不需要重啟中間件。
    3,可以自定義登錄界面,而不是借助于瀏覽器的窗口和HTTP BASIC方式。
    4,不好之處是,由于角色已經(jīng)在代碼或配置中綁定,無(wú)法動(dòng)態(tài)新增角色。


    大家如有不清楚與需要討論的地方,歡迎留言!

    本Blog所有內(nèi)容不得隨意轉(zhuǎn)載,版權(quán)屬于作者所有。如需轉(zhuǎn)載請(qǐng)與作者聯(lián)系( fastzch@163.com    QQ:9184314)。
    未經(jīng)許可的轉(zhuǎn)載,本人保留一切法律權(quán)益。
    一直以來(lái),發(fā)現(xiàn)有某些人完全不尊重我的勞動(dòng)成果,隨意轉(zhuǎn)載,提醒一下那些人小心哪天惹上官司。



    posted on 2010-04-28 09:56 Robin's Programming World 閱讀(3033) 評(píng)論(3)  編輯  收藏 所屬分類: JavaFlex & Flash

    評(píng)論:
    # re: BlazeDS自定義認(rèn)證與權(quán)限控制 2010-04-28 11:25 | 俏物悄語(yǔ)
    看見就撒嬌的撒  回復(fù)  更多評(píng)論
      
    # re: BlazeDS自定義認(rèn)證與權(quán)限控制[未登錄] 2014-03-11 13:16 | yxy
    <mx:RemoteObject id = "loginService" destination = "remoting_AMF_SecurityConstraint_Custom"這里的destination在哪里定義?是干什么的  回復(fù)  更多評(píng)論
      
    # re: BlazeDS自定義認(rèn)證與權(quán)限控制 2015-06-14 14:08 | 內(nèi)誰(shuí)
    主站蜘蛛池模板: 亚洲第一成年免费网站| 久久久久久一品道精品免费看| 在线观看免费视频资源| 亚洲不卡AV影片在线播放| 亚洲免费黄色网址| 久久久久久久99精品免费观看| 免费乱码中文字幕网站| 最新国产成人亚洲精品影院| 污污网站免费观看| 激情97综合亚洲色婷婷五| 亚洲A∨精品一区二区三区下载| 在线看无码的免费网站| 亚洲精品美女久久久久99| 色一情一乱一伦一视频免费看| 亚洲精品动漫免费二区| 亚洲尹人九九大色香蕉网站| 国产免费内射又粗又爽密桃视频| 国产美女做a免费视频软件| 亚洲人成网男女大片在线播放| 高清一区二区三区免费视频| 自拍偷自拍亚洲精品被多人伦好爽| 污污视频免费观看网站| 午夜精品在线免费观看| 亚洲二区在线视频| 国产精品久久久久久久久免费| 亚洲va久久久噜噜噜久久狠狠 | 色偷偷尼玛图亚洲综合| 99久久这里只精品国产免费| 18亚洲男同志videos网站| 国内精品久久久久影院免费 | 黄网站色视频免费观看45分钟| 麻豆国产精品入口免费观看| 亚洲人6666成人观看| 综合在线免费视频| 亚洲精品免费在线视频| 中文字幕在线免费观看| 亚洲日本中文字幕| 一级毛片免费视频| 亚洲系列中文字幕| 亚洲一区免费视频| 亚洲国产成人综合|