欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

How Tomcat Works(十三)

系統(tǒng) 1960 0

本文分析tomcat容器的安全管理,servlet技術支持通過配置部署描述器(web.xml文件)來對受限內(nèi)容進行訪問控制;servlet容器是通過一個名為驗證器的閥來支持安全限制的,當servlet容器啟動時,驗證器閥會被添加到Context容器的管道中。在調(diào)用Wrapper閥之前,會先調(diào)用驗證器閥,對當前用戶進行身份驗證;驗證器閥會調(diào)用Context容器的Realm對象的authenticate()方法,傳入用戶輸入的用戶名和密碼來對用戶進行身份驗證。

Realm對象是用來對用戶進行身份驗證的組件,它會對用戶輸入的用戶名和密碼對進行有效性判斷,通常與一個Context容器相關聯(lián);那么Realm對象是如何驗證用戶身份的呢?實際上,它保存了所有有效用戶的用戶名和密碼對,或者它會訪問存儲這些數(shù)據(jù)的存儲器。這些數(shù)據(jù)的具體存儲依賴于Realm對象的具體實現(xiàn),在tomcat中,有效用戶信息默認存儲在tomcat-user.xml文件中;當然也可以使用其他的針對其他資源驗證Realm對象實現(xiàn),比如關系數(shù)據(jù)庫

在tomcat中,Realm對象是org.apache.catalina.Realm接口的實例,與驗證相關的方法如下:

public Principal authenticate(String username, String credentials);

public Principal authenticate(String username, byte[] credentials);

public Principal authenticate(String username, String digest,
????????????????????????????????? String nonce, String nc, String cnonce,
????????????????????????????????? String qop, String realm,
????????????????????????????????? String md5a2);

public Principal authenticate(X509Certificate certs[]);

通常都會使用第一個重載方法。在Realm接口中,還有一個hasRole()方法,方法簽名如下:

public boolean hasRole(Principal principal, String role);

此外,Realm接口的getContainer()方法與settContainer()方法用來將Realm實例與一個Context實例相關聯(lián)

在tomcat中,Realm接口的基本實現(xiàn)形式是org.apache.catalina.realm.RealmBase類,該類是一個抽象類,org.apache.catalina.realm包還提供了RealmBase類的一些繼承類的實現(xiàn),包括JDBCRealm、JNDIRealm、MemoryRealm和UserDatabaseRealm類等。 默認情況下,會使用MemoryRealm類的實例作為驗證用的Realm對象。當?shù)谝淮握{(diào)用MemoryRealm實例時,它會讀取tomcat-user.xml文檔的內(nèi)容。

在tomcat中,java.security.Principal接口的實例為org.apache.catalina.realm.GenericPrincipal類,GenericPrincipal實例必須始終與一個Realm對象相關聯(lián),正如其兩個構(gòu)造函數(shù)所示:

public GenericPrincipal(Realm realm, String name, String password) {

??????? this(realm, name, password, null);

??? }

public GenericPrincipal(Realm realm, String name, String password,
??????????????????????????? List roles) {

??????? super();
??????? this.realm = realm;
??????? this.name = name;
??????? this.password = password;
??????? if (roles != null) {
??????????? this.roles = new String[roles.size()];
??????????? this.roles = (String[]) roles.toArray(this.roles);
??????????? if (this.roles.length > 0)
??????????????? Arrays.sort(this.roles);
??????? }

??? }

GenericPrincipal實例必須有一個用戶名和密碼對。此外,該用戶名和密碼對所對應的角色列表是可選的;然后可以調(diào)用其hasRole()方法,并傳入字符串形式的角色名來檢查該Principal對象是否擁有指定角色

public boolean hasRole(String role) {

??????? if (role == null)
??????????? return (false);
??????? return (Arrays.binarySearch(roles, role) >= 0);

??? }

下面我們來看一個簡單的Realm對象是怎樣工作的,里面采用了硬編碼的方式保存了兩個用戶名和密碼對

SimpleRealm類的源碼如下(略去了無關代碼)

      
        public
      
      
        class
      
       SimpleRealm 
      
        implements
      
      
         Realm {

  
      
      
        public
      
      
         SimpleRealm() {
    createUserDatabase();
  }

  
      
      
        private
      
      
         Container container;
  
      
      
        private
      
       ArrayList users = 
      
        new
      
      
         ArrayList();

  
      
      
        public
      
      
         Container getContainer() {
    
      
      
        return
      
      
         container;
  }

  
      
      
        public
      
      
        void
      
      
         setContainer(Container container) {
    
      
      
        this
      
      .container =
      
         container;
  }
  
      
      
        /**
      
      
        
   * 驗證用戶名和密碼,返回Principal類型對象
   
      
      
        */
      
      
        public
      
      
         Principal authenticate(String username, String credentials) {
    System.out.println(
      
      "SimpleRealm.authenticate()"
      
        );
    
      
      
        if
      
       (username==
      
        null
      
       || credentials==
      
        null
      
      
        )
      
      
      
        return
      
      
        null
      
      
        ;
    User user 
      
      =
      
         getUser(username, credentials);
    
      
      
        if
      
       (user==
      
        null
      
      
        )
      
      
      
        return
      
      
        null
      
      
        ;
    
      
      
        return
      
      
        new
      
       GenericPrincipal(
      
        this
      
      
        , user.username, user.password, user.getRoles());
  }
  
      
      
        /**
      
      
        
  * 判斷Principal類型對象是有擁有指定角色
  
      
      
        */
      
      
        public
      
      
        boolean
      
      
         hasRole(Principal principal, String role) {
    
      
      
        if
      
       ((principal == 
      
        null
      
      ) || (role == 
      
        null
      
      ) ||
      !(principal 
      
        instanceof
      
      
         GenericPrincipal))
      
      
      
        return
      
       (
      
        false
      
      
        );
    GenericPrincipal gp 
      
      =
      
         (GenericPrincipal) principal;
    
      
      
        if
      
       (!(gp.getRealm() == 
      
        this
      
      
        ))
      
      
      
        return
      
       (
      
        false
      
      
        );
    
      
      
        boolean
      
       result =
      
         gp.hasRole(role);
    
      
      
        return
      
      
         result;
  }


  
      
      
        private
      
      
         User getUser(String username, String password) {
    Iterator iterator 
      
      =
      
         users.iterator();
    
      
      
        while
      
      
         (iterator.hasNext()) {
      User user 
      
      =
      
         (User) iterator.next();
      
      
      
        if
      
       (user.username.equals(username) &&
      
         user.password.equals(password))
        
      
      
        return
      
      
         user;
    }
    
      
      
        return
      
      
        null
      
      
        ;
  }

  
      
      
        private
      
      
        void
      
      
         createUserDatabase() {
    User user1 
      
      = 
      
        new
      
       User("ken", "blackcomb"
      
        );
    user1.addRole(
      
      "manager"
      
        );
    user1.addRole(
      
      "programmer"
      
        );
    User user2 
      
      = 
      
        new
      
       User("cindy", "bamboo"
      
        );
    user2.addRole(
      
      "programmer"
      
        );

    users.add(user1);
    users.add(user2);
  }

  
      
      
        class
      
      
         User {

    
      
      
        public
      
      
         User(String username, String password) {
      
      
      
        this
      
      .username =
      
         username;
      
      
      
        this
      
      .password =
      
         password;
    }

    
      
      
        public
      
      
         String username;
    
      
      
        public
      
       ArrayList roles = 
      
        new
      
      
         ArrayList();
    
      
      
        public
      
      
         String password;

    
      
      
        public
      
      
        void
      
      
         addRole(String role) {
      roles.add(role);
    }
    
      
      
        public
      
      
         ArrayList getRoles() {
      
      
      
        return
      
      
         roles;
    }
  }

}
      
    

其中的authenticate()方法由驗證器調(diào)用,如果用戶提供的用戶名和密碼是無效的便返回null,否則返回代表該用戶的Principal對象

上面部分是描述Realm對象相關的,接下來描述與驗證器相關的實現(xiàn)。驗證器是org.apache.catalina.Authenticator接口的實例,Authenticator接口是一個標識接口,沒有聲明任何方法;在tomcat中提供了Authenticator接口的基本實現(xiàn)org.apache.catalina.authenticator.AuthenticatorBase類,同時AuthenticatorBase類還繼承了org.apache.catalina.valves.ValveBase類,也就是說,AuthenticatorBase類也是一個閥;在tomat中,提供了很多AuthenticatorBase類的繼承類,包括BasicAuthenticator類、FormAuthenticator類、DigestAuthenticator類和SSLAuthenticator類等;此外當tomcat用戶沒有指定驗證方法名時,NonLoginAuthenticator類用來對來訪者的身份進行驗證。

AuthenticatorBase類的invoke()方法會調(diào)用authenticate()抽象方法,后者的實現(xiàn)依賴于子類,這里類似與templet方法模式

那么在我們的web應用程序中,具體采用那個驗證器實現(xiàn)呢,這依賴于我們在web.xml文件中的配置(配置示例如下)

      
        <
      
      
        web-app
      
      
        >
      
      
        <
      
      
        security-constraint
      
      
        >
      
      
        <
      
      
        web-resource-collection
      
      
        >
      
      
        <
      
      
        web-resource-name
      
      
        >
      
      
          
            Member Area  
         
      
      
        </
      
      
        web-resource-name
      
      
        >
      
      
        <
      
      
        description
      
      
        >
      
      
          
            Only registered members can access this area.  
         
      
      
        </
      
      
        description
      
      
        >
      
      
        <
      
      
        url-pattern
      
      
        >
      
      /member/*
      
        </
      
      
        url-pattern
      
      
        >
      
      
        <
      
      
        http-method
      
      
        >
      
      GET
      
        </
      
      
        http-method
      
      
        >
      
      
        <
      
      
        http-method
      
      
        >
      
      POST
      
        </
      
      
        http-method
      
      
        >
      
      
        </
      
      
        web-resource-collection
      
      
        >
      
      
        <
      
      
        auth-constraint
      
      
        >
      
      
        <
      
      
        role-name
      
      
        >
      
      member
      
        </
      
      
        role-name
      
      
        >
      
      
        </
      
      
        auth-constraint
      
      
        >
      
      
        </
      
      
        security-constraint
      
      
        >
      
      
        <
      
      
        login-config
      
      
        >
      
      
        <
      
      
        auth-method
      
      
        >
      
      BASIC
      
        </
      
      
        auth-method
      
      
        >
      
      
        </
      
      
        login-config
      
      
        >
      
      
        <
      
      
        security-role
      
      
        >
      
      
        <
      
      
        role-name
      
      
        >
      
      member
      
        </
      
      
        role-name
      
      
        >
      
      
        </
      
      
        security-role
      
      
        >
      
      
        </
      
      
        web-app
      
      
        >
      
    

上面示例是采用BASIC驗證,也可以設置為FORM、DIGEST或CLIENT-CERT等,分別對應不同的驗證器類(BasicAuthenticator類、FormAuthenticator類、DigestAuthenticator類和SSLAuthenticator類),若沒有設置auth-method元素,則LoginConfig對象auth-method屬性的默認值為NONE,使用NonLoginAuthenticator進行安全驗證。(注:LoginConfig對象封裝了Realm對象名和要使用的身份驗證方法)

最后我們來描述一個Context容器實例是如何將驗證器閥的,這里介紹的是一個SimpleContextConfig類,它是作為Context容器實例的監(jiān)聽器,在監(jiān)聽方法lifecycleEvent()中,調(diào)用authenticatorConfig()方法實例化BasicAuthenticator類,并將其作為閥添加到StandardContext實例的管道中

下面是SimpleContextConfig類的authenticatorConfig()方法實現(xiàn)

      
        private
      
      
        synchronized
      
      
        void
      
      
         authenticatorConfig() {
    
      
      
        //
      
      
         Does this Context require an Authenticator?
      
      
    SecurityConstraint constraints[] =
      
         context.findConstraints();
    
      
      
        if
      
       ((constraints == 
      
        null
      
      ) || (constraints.length == 0
      
        ))
      
      
      
        return
      
      
        ;
    LoginConfig loginConfig 
      
      =
      
         context.getLoginConfig();
    
      
      
        if
      
       (loginConfig == 
      
        null
      
      
        ) {
      loginConfig 
      
      = 
      
        new
      
       LoginConfig("NONE", 
      
        null
      
      , 
      
        null
      
      , 
      
        null
      
      
        );
      context.setLoginConfig(loginConfig);
    }

    
      
      
        //
      
      
         Has an authenticator been configured already?
      
      
    Pipeline pipeline =
      
         ((StandardContext) context).getPipeline();
    
      
      
        if
      
       (pipeline != 
      
        null
      
      
        ) {
      Valve basic 
      
      =
      
         pipeline.getBasic();
      
      
      
        if
      
       ((basic != 
      
        null
      
      ) && (basic 
      
        instanceof
      
      
         Authenticator))
        
      
      
        return
      
      
        ;
      Valve valves[] 
      
      =
      
         pipeline.getValves();
      
      
      
        for
      
       (
      
        int
      
       i = 0; i < valves.length; i++
      
        ) {
        
      
      
        if
      
       (valves[i] 
      
        instanceof
      
      
         Authenticator)
        
      
      
        return
      
      
        ;
      }
    }
    
      
      
        else
      
       { 
      
        //
      
      
         no Pipeline, cannot install authenticator valve
      
      
        return
      
      
        ;
    }

    
      
      
        //
      
      
         Has a Realm been configured for us to authenticate against?
      
      
        if
      
       (context.getRealm() == 
      
        null
      
      
        ) {
      
      
      
        return
      
      
        ;
    }

    
      
      
        //
      
      
         Identify the class name of the Valve we should configure
      
      
    String authenticatorName = "org.apache.catalina.authenticator.BasicAuthenticator"
      
        ;
    
      
      
        //
      
      
         Instantiate and install an Authenticator of the requested class
      
      
    Valve authenticator = 
      
        null
      
      
        ;
    
      
      
        try
      
      
         {
      Class authenticatorClass 
      
      =
      
         Class.forName(authenticatorName);
      authenticator 
      
      =
      
         (Valve) authenticatorClass.newInstance();
      ((StandardContext) context).addValve(authenticator);
      System.out.println(
      
      "Added authenticator valve to Context"
      
        );
    }
    
      
      
        catch
      
      
         (Throwable t) {
    }
  }
      
    

---------------------------------------------------------------------------?

本系列How Tomcat Works系本人原創(chuàng)?

轉(zhuǎn)載請注明出處 博客園 刺猬的溫馴?

本人郵箱: ? chenying998179 # 163.com ( #改為@

本文鏈接 http://www.cnblogs.com/chenying99/p/3242277.html

How Tomcat Works(十三)


更多文章、技術交流、商務合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 欧美精品综合一区二区三区 | 欧美日韩免费在线观看 | 特色特色大片在线 | 亚洲国产专区 | 亚洲精品乱码久久久久久花季 | 亚洲成人av一区二区 | 国产片侵犯亲女视频播放 | 超级成人97碰碰碰免费 | 羞羞的网址 | 四虎亚洲| 五月婷婷欧美 | 精品视频一区二区观看 | 亚洲精品久久久久影院 | 免费精品美女久久久久久久久久 | 成人国产网站 | 在线视频二区 | 久久伊人久久 | 亚洲一区国产视频 | 日本免费三级网站 | 成人午夜免费福利视频 | 亚洲激情 欧美 | 精品欧美一区二区三区 | 视频精品一区 | 日韩艹 | 色屁屁www免费看视频影院 | 永久免费在线播放 | 日韩欧美一二三区 | 久久国产美女 | 亚洲成av人片在线观看 | 欧美精品一区二区在线观看 | 成人福利视频 | 国产高清视频一区二区 | 欧美综合久久 | 亚洲精品视频一区二区三区 | 久操精品在线观看 | 国产91影院 | 一区二区三区四区国产 | 国产视频高清在线观看 | 久久精品国产99国产精品澳门 | 污视频免费看网站 | 狠狠色噜噜狠狠狠狠97老肥女 |