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

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

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

    tangtb

    Hadoop,SpringMVC,ExtJs,Struts2,Spring,SpringSecurity,Hibernate,Struts
    posts - 25, comments - 88, trackbacks - 0, articles - 0
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    【轉載】集成ACEGI 進行權限控制

    Posted on 2008-08-06 10:41 tangtb 閱讀(1647) 評論(0)  編輯  收藏 所屬分類: SpringSpring Security

    集成ACEGI 進行權限控制

    一. 簡單介紹

     1.1 本文目的

    集成Acegi到自己的項目中, 并且將用戶信息和權限放到數據庫, 提供方法允許權限動態變化,變化后自動加載最新的權限

    本文介紹Acegi例子的時候采用的是acegi-security-samples-tutorial-1.0.6.war

    閱讀本文需要對Spring有一定的了解, 如果你還沒有接觸過, 有些地方可能不容易理解, 這時候可能需要參考本文后附的Spring地址, 先了解一下Spring的基本知識.

    本文使用的是Mysql數據庫, 如果你使用其他的數據庫, 可能需要修改相應的SQL.

    1.2 安裝與配置

    項目主頁: http://www.acegisecurity.org/

    下載地址: http://sourceforge.net/project/showfiles.php?group_id=104215

    解壓文件后, 將acegi-security-samples-tutorial-1.0.6.war復制Your_Tomcat_Path/webapps/

    啟動Tomcat, 訪問http://localhost:8080/acegi-security-samples-tutorial-1.0.6/

    點擊頁面上任何一個鏈接,都需要用戶登錄后訪問, 可以在頁面上看到可用的用戶名和密碼.

    二. 開始集成到自己的程序中

    2.1 將用戶和角色放在數據庫中

    可能是為了演示方便, 簡單的展示Acegi如何控制權限, 而不依賴于任何數據庫, ACEGI給出的例子采用InMemoryDaoImpl獲取用戶信息, 用戶和角色信息放在WEB-INF/users.properties 文件中, InMemoryDaoImpl 一次性的從該配置文件中讀出用戶和角色信息, 格式是: 用戶名=密碼, 角色名, 如第一行是:

    marissa=koala,ROLE_SUPERVISOR

    就是說marissa的密碼是koala, 并且他的角色是ROLE_SUPERVISOR

    對這個文件的解析是通過applicationContext-acegi-security.xml中如下的設置進行的:

     1 <!-- UserDetailsService is the most commonly frequently
         Acegi Security interface implemented by end users 
    -->
     2 <bean id="userDetailsService"
     3 class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
     4 <property name="userProperties">
     5 <bean
     6 class="org.springframework.beans.factory.config.PropertiesFactoryBean">
     7 <property name="location"
     8 value="classpath:sers.properties" />
     9 </bean>
    10 </property>
    11 </bean>
    12 
    13 


    除了InMemoryDaoImpl之外, ACEGI還提供了Jdbc和 ldap的支持, 由于使用數據庫進行驗證比較常見, 下面僅就jdbc實現做出介紹.

    不管是InMemoryDaoImpl還是JdbcDaoImpl都是實現了UserDetailsService接口, 而這個接口里只定義了一個方法: UserDetails loadUserByUsername(String username) 就是根據用戶名加載UserDetails對象, UserDetails也是一個接口, 定義了一個用戶所需要的基本信息, 包括: username, password, authorities等信息

    2.1.1 直接使用JdbcDaoImpl 訪問數據庫中的用戶信息

    如果ACEGI提供的信息滿足你的需要, 也就是說你只需要用戶的username, password等信息, 你可以直接使用ACEGI提供的Schema, 這樣, 不需要任何變動, JdbcDaoImpl就可以使用了.

    如果你的數據庫已經定義好了, 或者不想使用ACEGI提供的Schema,那么你也可以自定義JdbcDaoImpl的查詢語句

     1         <property name="usersByUsernameQuery">
     2 <value>
     3 SELECT email, password, enabled from user u where email = ?
     4 </value>
     5 </property>
     6 <property name="authoritiesByUsernameQuery">
     7 <value>
     8 SELECT u.email, r.role_name FROM user_role ur, user u, role r WHERE
     9 ur.user_id = u.user_id and ur.role_id = r.role_id and u.email = ?
    10 </value>
    11 </property>

    2.1.2 擴展JdbcDaoImpl獲取更多用戶信息

    如果上面提到的定制查詢SQL語句不能提供足夠的靈活性, 那么你可能就需要定義一個JdbcDaoImpl的子類, 如果變動不大, 通過覆蓋initMappingSqlQueries方法重新定義MappingSqlQuery的實例. 而如果你需要獲取更多信息, 比如userId, companyId等, 那就需要做更多的改動, 第一種改動不大, 所以不具體介紹, 下面以第二種改動為例,介紹如何實現這種需求.

    我們需要三張表User, Role, User_Role, 具體的SQL如下:

     1 1 #
     2  2 # Structure for the `role` table :
     3  3 #
     4  4 DROP TABLE IF EXISTS `role`;
     5  5 CREATE TABLE `role` (
     6  6 `role_id` int(11NOT NULL auto_increment,
     7  7 `role_name` varchar(50default NULL,
     8  8 `description` varchar(20default NULL,
     9  9 `enabled` tinyint(1NOT NULL default '1',
    10 10 PRIMARY KEY  (`role_id`)
    11 11 );
    12 12 #
    13 13 # Structure for the `usertable :
    14 14 #
    15 15 DROP TABLE IF EXISTS `user`;
    16 16 CREATE TABLE `user` (
    17 17 `user_idint(11NOT NULL auto_increment,
    18 18 `company_id` int(11default NULL,
    19 19 `email` varchar(200default NULL,
    20 20 `password` varchar(10default NULL,
    21 21 `enabled` tinyint(1default NULL,
    22 22 PRIMARY KEY  (`user_id`)
    23 23 );
    24 24 #
    25 25 # Structure for the `user_role` table :
    26 26 #
    27 27 DROP TABLE IF EXISTS `user_role`;
    28 28 CREATE TABLE `user_role` (
    29 29 `user_role_id` int(11NOT NULL auto_increment,
    30 30 `user_idvarchar(50NOT NULL,
    31 31 `role_id` int(11NOT NULL,
    32 32 PRIMARY KEY  (`user_role_id`)
    33 33 );

    前面講過, UserDetailsService接口中只定義了一個方法: UserDetails loadUserByUsername(String username), UserDetails中不存在我們需要的userId 和companyId等信息, 所以我們首先需要擴展UserDetails接口, 并擴展org.acegisecurity.userdetails.User:

    IUserDetails.java


    UserDetailsImpl.java

     1 package org.security;
     2 import org.acegisecurity.GrantedAuthority;
     3 import org.acegisecurity.userdetails.User;
     4 /**
     5  * The class <code>UserDetailsImpl</code> extends the
        * org.acegisecurity.userdetails.User class, and provides
        * additional userId, companyId information
     6  * @author wade
     7  * 
     8  * @see IUserDetails, User
     9  */
    10 public class UserDetailsImpl extends User implements IUserDetails{
    11 private int user_id;
    12 private int company_id;
    13 private String username;
    14 private GrantedAuthority[] authorities;
    15 public UserDetailsImpl(String username, String password, boolean enabled,
    16 boolean accountNonExpired, boolean credentialsNonExpired,
    17 boolean accountNonLocked, GrantedAuthority[] authorities)
    18 throws IllegalArgumentException {
    19 super(username, password, enabled, accountNonExpired, credentialsNonExpired,
    20 accountNonLocked, authorities);
    21 setUsername(username);
    22 setAuthorities(authorities);
    23 }
    24 public UserDetailsImpl(int userid, int companyid, String username,
                                            String password, 
    boolean enabled,
    25 boolean accountNonExpired, boolean credentialsNonExpired,
    26 boolean accountNonLocked, GrantedAuthority[] authorities)
    27 throws IllegalArgumentException {
    28 super(username, password, enabled, accountNonExpired, credentialsNonExpired,
    29 accountNonLocked, authorities);
    30 this.user_id = userid;
    31 this.company_id = companyid;
    32 setUsername(username);
    33 setAuthorities(authorities);
    34 }
    35 public int getUserId() {
    36 return user_id;
    37 }
    38 public void setUserId(int user_id) {
    39 this.user_id = user_id;
    40 }
    41 public int getCompanyId() {
    42 return company_id;
    43 }
    44 public void setCompanyId(int company_id) {
    45 this.company_id = company_id;
    46 }
    47 public String getUsername() {
    48 return username;
    49 }
    50 public void setUsername(String username) {
    51 this.username = username;
    52 }
    53 public GrantedAuthority[] getAuthorities() {
    54 return authorities;
    55 }
    56 public void setAuthorities(GrantedAuthority[] authorities) {
    57 this.authorities = authorities;
    58 }
    59 }


    到此為止, 我們已經準備好了存放用戶信息的類, 下面就開始動手修改取用戶數據的代碼.

    假設我們用下面的SQL取用戶信息:

    SELECT u.user_id, u.company_id, email, password, enabled
    FROM role r, user_role ur, user u
    WHERE r.role_id = ur.role_id
    and ur.user_id = u.user_id
    and email = ?
    limit 1

    用下面的SQL取用戶具有的Role列表

    SELECT u.email, r.role_name
    FROM user_role ur, user u, role r
    WHERE ur.user_id = u.user_id
    and ur.role_id = r.role_id
    and u.email = ?


    我們需要修改的主要是兩部分:

    1. 取用戶和用戶角色的MappingSqlQuery, 增加了查詢的userId和companyId.

    2. loadUserByUsername方法, 修改了返回的對象類型,和很少的內部代碼.

    AcegiJdbcDaoImpl.java

      1 package org.security.acegi;
      2 
      3 import java.sql.ResultSet;
      4 
      5 import java.sql.SQLException;
      6 
      7 import java.sql.Types;
      8 
      9 import java.util.List;
     10 
     11 import javax.sql.DataSource;
     12 
     13 import org.acegisecurity.GrantedAuthority;
     14 
     15 import org.acegisecurity.GrantedAuthorityImpl;
     16 
     17 import org.acegisecurity.userdetails.UsernameNotFoundException;
     18 
     19 import org.acegisecurity.userdetails.jdbc.JdbcDaoImpl;
     20 
     21 import org.security.IUserDetails;
     22 
     23 import org.security.UserDetailsImpl;
     24 
     25 import org.springframework.dao.DataAccessException;
     26 
     27 import org.springframework.jdbc.core.SqlParameter;
     28 
     29 import org.springframework.jdbc.object.MappingSqlQuery;
     30 
     31 /**
     32  * The class AcegiJdbcDaoImpl provides the method to
         *  get IUserDetail information from db which contains userId,
         * companyId and UserDetail information.
     33  * 
     34  * @author wade
     35  *
     36  */
     37 public class AcegiJdbcDaoImpl extends JdbcDaoImpl {
     38 
     39 public static final String DEF_USERS_BY_USERNAME_QUERY =
     40 
     41 "SELECT u.user_id, u.company_id, email, password, enabled                         "+"from role r, user_role ur, user u where r.role_id = ur.role_id "+"and ur.user_id = u.user_id and email = ? limit 1";
     42 
     43 public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY =
     44 
     45 "SELECT username,authority FROM authorities WHERE username = ?";
     46 
     47 protected MappingSqlQuery rolesByUsernameMapping;
     48 
     49 protected MappingSqlQuery usersByNameMapping;
     50 
     51 private String authoritiesByUsernameQuery;
     52 
     53 private String rolePrefix = "";
     54 
     55 private String usersByUsernameQuery;
     56 
     57 private boolean usernameBasedPrimaryKey = true;
     58 
     59 public AcegiJdbcDaoImpl(){
     60 
     61 usersByUsernameQuery = DEF_USERS_BY_USERNAME_QUERY;
     62 
     63 authoritiesByUsernameQuery = DEF_AUTHORITIES_BY_USERNAME_QUERY;
     64 
     65 }
     66 
     67 public String getAuthoritiesByUsernameQuery() {
     68 
     69 return authoritiesByUsernameQuery;
     70 
     71 }
     72 
     73 public String getRolePrefix() {
     74 
     75 return rolePrefix;
     76 
     77 }
     78 
     79 public String getUsersByUsernameQuery() {
     80 
     81 return usersByUsernameQuery;
     82 
     83 }
     84 
     85 protected void initMappingSqlQueries() {
     86 
     87 this.usersByNameMapping = new UsersByUsernameMapping(getDataSource());
     88 
     89 this.rolesByUsernameMapping = new AuthoritiesByUsernameMapping(getDataSource());
     90 
     91 }
     92 
     93 /**
     94      * Allows the default query string used to retrieve authorities based on
             *      username to be overriden, if
     95      * default table or column names need to be changed. The default query is {@link
     96      * #DEF_AUTHORITIES_BY_USERNAME_QUERY}; when modifying this query,
             *      ensure that all returned columns are mapped
     97      * back to the same column names as in the default query.
     98      *
     99      * @param queryString The query string to set
    100      */
    101 public void setAuthoritiesByUsernameQuery(String queryString) {
    102 
    103 authoritiesByUsernameQuery = queryString;
    104 
    105 }
    106 
    107 /**
    108      * Allows a default role prefix to be specified. If this is set to a non-empty value,
             then it is
    109      * automatically prepended to any roles read in from the db. This may for example be used to add the
    110      * <code>ROLE_</code> prefix expected to exist in role names (by default) by some other Acegi Security framework
    111      * classes, in the case that the prefix is not already present in the db.
    112      *
    113      * @param rolePrefix the new prefix
    114      */
    115 public void setRolePrefix(String rolePrefix) {
    116 
    117 this.rolePrefix = rolePrefix;
    118 
    119 }
    120 
    121 /**
    122      * If <code>true</code> (the default), indicates the {@link #getUsersByUsernameQuery()} returns a username
    123      * in response to a query. If <code>false</code>, indicates that a primary key is used instead. If set to
    124      * <code>true</code>, the class will use the database-derived username in the returned <code>UserDetailsImpl</code>.
    125      * If <code>false</code>, the class will use the {@link #loadUserByUsername(String)} derived username in the
    126      * returned <code>UserDetailsImpl</code>.
    127      *
    128      * @param usernameBasedPrimaryKey <code>true</code> if the mapping queries return the username <code>String</code>,
    129      *        or <code>false</code> if the mapping returns a database primary key.
    130      */
    131 public void setUsernameBasedPrimaryKey(boolean usernameBasedPrimaryKey) {
    132 
    133 this.usernameBasedPrimaryKey = usernameBasedPrimaryKey;
    134 
    135 }
    136 
    137 /**
    138      * Allows the default query string used to retrieve users based on username to be overriden, if default
    139      * table or column names need to be changed. The default query is {@link #DEF_USERS_BY_USERNAME_QUERY}; when
    140      * modifying this query, ensure that all returned columns are mapped back to the same column names as in the
    141      * default query. If the 'enabled' column does not exist in the source db, a permanent true value for this column
    142      * may be returned by using a query similar to <br><pre>
    143      * "SELECT username,password,'true' as enabled FROM users WHERE username = ?"</pre>
    144      *
    145      * @param usersByUsernameQueryString The query string to set
    146      */
    147 public void setUsersByUsernameQuery(String usersByUsernameQueryString) {
    148 
    149 this.usersByUsernameQuery = usersByUsernameQueryString;
    150 
    151 }
    152 
    153 public IUserDetails loadUserByUsername(String username)
    154 
    155 throws UsernameNotFoundException, DataAccessException {
    156 
    157 List users = usersByNameMapping.execute(username);
    158 
    159 if (users.size() == 0) {
    160 
    161 throw new UsernameNotFoundException("User not found");
    162 
    163 }
    164 
    165 IUserDetails user = (IUserDetails) users.get(0); // contains no GrantedAuthority[]
    166 List dbAuths = rolesByUsernameMapping.execute(user.getUsername());
    167 addCustomAuthorities(user.getUsername(), dbAuths);
    168 if (dbAuths.size() == 0) {
    169 
    170 throw new UsernameNotFoundException("User has no GrantedAuthority");
    171 
    172 }
    173 
    174 GrantedAuthority[] arrayAuths = (GrantedAuthority[]) dbAuths.toArray(new GrantedAuthority[dbAuths.size()]);
    175 
    176 user.setAuthorities(arrayAuths);
    177 
    178 if (!usernameBasedPrimaryKey) {
    179 
    180 user.setUsername(username);
    181 
    182 }
    183 
    184 return user;
    185 
    186 }
    187 
    188 /**
    189      * Query object to look up a user's authorities.
    190      */
    191 protected class AuthoritiesByUsernameMapping extends MappingSqlQuery {
    192 
    193 protected AuthoritiesByUsernameMapping(DataSource ds) {
    194 
    195 super(ds, authoritiesByUsernameQuery);
    196 
    197 declareParameter(new SqlParameter(Types.VARCHAR));
    198 
    199 compile();
    200 
    201 }
    202 
    203 protected Object mapRow(ResultSet rs, int rownum)
    204 
    205 throws SQLException {
    206 
    207 String roleName = rolePrefix + rs.getString(2);
    208 
    209 GrantedAuthorityImpl authority = new GrantedAuthorityImpl(roleName);
    210 
    211 return authority;
    212 
    213 }
    214 
    215 }
    216 
    217 /**
    218      * Query object to look up a user.
    219      */
    220 protected class UsersByUsernameMapping extends MappingSqlQuery {
    221 
    222 protected UsersByUsernameMapping(DataSource ds) {
    223 
    224 super(ds, usersByUsernameQuery);
    225 
    226 declareParameter(new SqlParameter(Types.VARCHAR));
    227 
    228 compile();
    229 
    230 }
    231 
    232 protected Object mapRow(ResultSet rs, int rownum)
    233 
    234 throws SQLException {
    235 
    236 int user_id = rs.getInt(1);
    237 
    238 int company_id = rs.getInt(2);
    239 
    240 String username = rs.getString(3);
    241 
    242 String password = rs.getString(4);
    243 
    244 boolean enabled = rs.getBoolean(5);
    245 
    246 IUserDetails user = new UserDetailsImpl(username, password, enabled, truetruetrue,
    247 
    248 new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")});
    249 
    250 user.setUserId(user_id);
    251 
    252 user.setCompanyId(company_id);
    253 
    254 return user;
    255 
    256 }
    257 
    258 }
    259 
    260 }


    修改spring配置, 使用我們新建立的類:

     1 <bean id="userDetailsService"
     2 class="org.security.acegi.AcegiJdbcDaoImpl">
     3 <property name="dataSource">
     4 <ref bean="dataSource" />
     5 </property>
     6 <property name="usersByUsernameQuery">
     7 <value>
     8 SELECT u.user_id, u.company_id, email, password, enabled
     9 from role r, user_role ur, user u where r.role_id = ur.role_id and ur.user_id = u.user_id
    10 and email = ?
    11 limit 1
    12 </value>
    13 </property>
    14 <property name="authoritiesByUsernameQuery">
    15 <value>
    16 SELECT u.email, r.role_name FROM user_role ur, user u, role r WHERE
    17 ur.user_id = u.user_id and ur.role_id = r.role_id and u.email = ?
    18 </value>
    19 </property>
    20 </bean>


    好了, 如果再有用戶登錄,就會調用我們的loadUserByUsername, 從數據庫中讀取用戶數據了, 那用戶的權限都有什么呢? 一個用戶又對應著哪些ROLE呢? 下面先講一下ACEGI 例子中的權限設置

    2.2 將權限放在數據庫中

    截止到1.0.6版, Acegi沒有提供直接從數據庫讀取權限的方法, 而是采用通過如下的配置設置權限:

     1     <bean id="filterInvocationInterceptor"
     2 class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
     3 <property name="authenticationManager" ref="authenticationManager" />
     4 <property name="accessDecisionManager">
     5 <bean class="org.acegisecurity.vote.AffirmativeBased">
     6 <property name="allowIfAllAbstainDecisions" value="false" />
     7 <property name="decisionVoters">
     8 <list>
     9 <bean class="org.acegisecurity.vote.RoleVoter" />
    10 <bean class="org.acegisecurity.vote.AuthenticatedVoter" />
    11 </list>
    12 </property>
    13 </bean>
    14 </property>
    15 <property name="objectDefinitionSource">
    16 <value><![CDATA[
    17 
    18 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
    19 
    20 PATTERN_TYPE_APACHE_ANT
    21 
    22 /secure/extreme/**=ROLE_SUPERVISOR
    23 
    24 /secure/**=IS_AUTHENTICATED_REMEMBERED
    25 
    26 /project/**=IS_AUTHENTICATED_REMEMBERED
    27 
    28 /task/**=ROLE_DEVELOPER
    29 
    30 /**=IS_AUTHENTICATED_ANONYMOUSLY
    31 
    32 ]]></value>
    33 </property>
    34 </bean>


    而對大部分項目, 將權限放在數據庫中可能是更靈活的, 為此, 我們需要寫一個類去讀取權限, 為了使這個類盡量簡單, 我們把它做成PathBasedFilterInvocationDefinitionMap和RegExpBasedFilterInvocationDefinitionMap的代理類, PathBasedFilterInvocationDefinitionMap 采用的是Ant Path 風格的匹配方式, 而RegExpBasedFilterInvocationDefinitionMap采用的是Perl5風格的匹配方式. 用戶可以通過在配置文件中設置來選擇具體比較方式, 默認的比較方式是Ant Path 風格的匹配方式.

    這樣我們需要做的就是讀取權限列表, 并放到相應的代理類里面, 而具體的比較則由代理類進行.

    需要的表結構: Resource, Role_Resource

     1 DROP TABLE IF EXISTS `resource`;
     2 
     3 CREATE TABLE `resource` (
     4 
     5 `resource_id` int(11NOT NULL auto_increment,
     6 
     7 `parent_resource_id` int(11default NULL,
     8 
     9 `resource_name` varchar(50default NULL,
    10 
    11 `description` varchar(100default NULL,
    12 
    13 PRIMARY KEY  (`resource_id`)
    14 
    15 );
    16 
    17 #
    18 
    19 # Structure for the `resource_role` table :
    20 
    21 #
    22 
    23 DROP TABLE IF EXISTS `resource_role`;
    24 
    25 CREATE TABLE `resource_role` (
    26 
    27 `resource_role_id` int(11NOT NULL auto_increment,
    28 
    29 `resource_id` int(11NOT NULL,
    30 
    31 `role_id` int(11NOT NULL,
    32 
    33 PRIMARY KEY  (`resource_role_id`)
    34 
    35 );


    添加我們的類:

    AcegiJdbcDefinitionSourceImpl.java

      1 package org.security.acegi;
      2 
      3 import java.sql.ResultSet;
      4 
      5 import java.sql.SQLException;
      6 
      7 import java.util.HashMap;
      8 
      9 import java.util.Iterator;
     10 
     11 import java.util.List;
     12 
     13 import java.util.Map;
     14 
     15 import javax.sql.DataSource;
     16 
     17 import org.acegisecurity.ConfigAttributeDefinition;
     18 
     19 import org.acegisecurity.SecurityConfig;
     20 
     21 import org.acegisecurity.intercept.web.FilterInvocationDefinitionMap;
     22 
     23 import org.acegisecurity.intercept.web.FilterInvocationDefinitionSource;
     24 
     25 import org.acegisecurity.intercept.web.PathBasedFilterInvocationDefinitionMap;
     26 
     27 import org.acegisecurity.intercept.web.RegExpBasedFilterInvocationDefinitionMap;
     28 
     29 import org.apache.commons.logging.Log;
     30 
     31 import org.apache.commons.logging.LogFactory;
     32 
     33 import org.security.IResourceRole;
     34 
     35 import org.security.ResourceRoleImpl;
     36 
     37 import org.security.event.IPermissionListener;
     38 
     39 import org.security.event.PermissionEventPublisher;
     40 
     41 import org.springframework.beans.factory.InitializingBean;
     42 
     43 import org.springframework.jdbc.core.support.JdbcDaoSupport;
     44 
     45 import org.springframework.jdbc.object.MappingSqlQuery;
     46 
     47 /**
     48  * 
     49  * The class <code>AcegiJdbcDefinitionSourceImpl</code> is proxy to
     50  * PathBasedFilterInvocationDefinitionMap or RegExpBasedFilterInvocationDefinitionMap, This class get the permission
     51  * settings from the database, the default sql script is: SELECT resource, role
     52  * FROM role_permission, if it doesn't match your needs, changed it in bean
     53  * setting. <br>
     54  * 
     55  * <br>
     56  * $log$<br>
     57  * <br>
     58  * 
     59  * @author $Author: wade $
     60  * @see
     61  */
     62 public class AcegiJdbcDefinitionSourceImpl extends JdbcDaoSupport implements
     63 
     64 InitializingBean, FilterInvocationDefinitionSource{
     65 
     66 private Log logger = LogFactory.getLog(this.getClass());
     67 
     68 public static final String DEF_PERMISSIONS_QUERY = "SELECT resource, role FROM role_permission";
     69 
     70 /** The Perl5 expression */
     71 String PERL5_KEY = "PATTERN_TYPE_PERL5";
     72 
     73 /** The ant path expression */
     74 String ANT_PATH_KEY = "PATTERN_TYPE_APACHE_ANT";
     75 
     76 /* Set default to Ant Path Expression*/
     77 private String resourceExpression = ANT_PATH_KEY;
     78 
     79 private boolean convertUrlToLowercaseBeforeComparison = false;
     80 
     81 private FilterInvocationDefinitionMap definitionSource = null;
     82 
     83 private String permissionsQuery;
     84 
     85 private String rolePrefix = "";
     86 
     87 public AcegiJdbcDefinitionSourceImpl() {
     88 
     89 permissionsQuery = DEF_PERMISSIONS_QUERY;
     90 
     91 }
     92 
     93 public String getAuthoritiesByUsernameQuery() {
     94 
     95 return permissionsQuery;
     96 
     97 }
     98 
     99 public String getRolePrefix() {
    100 
    101 return rolePrefix;
    102 
    103 }
    104 
    105 /**
    106      * Allows the default query string used to retrieve permissions to be
    107      * overriden, if default table or column names need to be changed. The
    108      * default query is {@link #DEF_PERMISSIONS_QUERY}; when modifying this
    109      * query, ensure that all returned columns are mapped back to the same
    110      * column names as in the default query.
    111      * 
    112      * @param queryString
    113      *            The query string to set
    114      */
    115 public void setPermissionsQuery(String queryString) {
    116 
    117 permissionsQuery = queryString;
    118 
    119 }
    120 
    121 /**
    122      * Allows a default role prefix to be specified. If this is set to a
    123      * non-empty value, then it is automatically prepended to any roles read in
    124      * from the db. This may for example be used to add the <code>ROLE_</code>
    125      * prefix expected to exist in role names (by default) by some other Acegi
    126      * Security framework classes, in the case that the prefix is not already
    127      * present in the db.
    128      * 
    129      * @param rolePrefix
    130      *            the new prefix
    131      */
    132 public void setRolePrefix(String rolePrefix) {
    133 
    134 this.rolePrefix = rolePrefix;
    135 
    136 }
    137 
    138 /**
    139      * Init the permission list from db
    140      * 
    141      */
    142 protected void initMap() {
    143 
    144 // return if we have got the latest permission list
    145 if (definitionSource != null) {
    146 
    147 return;
    148 
    149 }
    150 
    151 logger.debug("getting permissions from db");
    152 
    153 if (PERL5_KEY.equals(getResourceExpression())) {
    154 
    155 definitionSource = new RegExpBasedFilterInvocationDefinitionMap();
    156 
    157 else if (ANT_PATH_KEY.equals(getResourceExpression())) {
    158 
    159 definitionSource = new PathBasedFilterInvocationDefinitionMap();
    160 
    161 else {
    162 
    163 throw new IllegalArgumentException("wrong resourceExpression value");
    164 
    165 }
    166 
    167 definitionSource.setConvertUrlToLowercaseBeforeComparison(isConvertUrlToLowercaseBeforeComparison());
    168 
    169 MappingSqlQuery permissionsMapping = new PermissionsMapping(
    170 
    171 getDataSource());
    172 
    173 List<IResourceRole> resources = permissionsMapping.execute();
    174 
    175 Map<String, String> map = new HashMap<String, String>();
    176 
    177 for (int i = 0; i < resources.size(); i++) {
    178 
    179 ConfigAttributeDefinition defn = new ConfigAttributeDefinition();
    180 
    181 String resource = resources.get(i).getResource();
    182 
    183 if (map.containsKey(resource)) {
    184 
    185 continue;
    186 
    187 else {
    188 
    189 map.put(resource, resource);
    190 
    191 }
    192 
    193 for (int j = i; j < resources.size(); j++) {
    194 
    195 IResourceRole resourceRole = resources.get(j);
    196 
    197 if (resource.equals(resourceRole.getResource())) {
    198 
    199 defn.addConfigAttribute(new SecurityConfig(resourceRole
    200 
    201 .getRole()));
    202 
    203 // logger.debug("added role: " + resourceRole.getRole());
    204 }
    205 }
    206 definitionSource.addSecureUrl(resources.get(i).getResource(), defn);
    207 // logger.debug("added roles to :" +
    208 // resources.get(i).getResource());
    209 }
    210 }
    211 /**
    212      * Query object to look up a user's authorities.
    213      */
    214 protected class PermissionsMapping extends MappingSqlQuery {
    215 
    216 protected PermissionsMapping(DataSource ds) {
    217 
    218 super(ds, permissionsQuery);
    219 
    220 compile();
    221 
    222 }
    223 
    224 protected IResourceRole mapRow(ResultSet rs, int rownum)
    225 
    226 throws SQLException {
    227 
    228 String resource = rs.getString(1);
    229 
    230 String role = rolePrefix + rs.getString(2);
    231 
    232 IResourceRole resourceRole = new ResourceRoleImpl(resource, role);
    233 
    234 return resourceRole;
    235 
    236 }
    237 
    238 }
    239 
    240 public ConfigAttributeDefinition getAttributes(Object object)
    241 
    242 throws IllegalArgumentException {
    243 
    244 initMap();
    245 
    246 if (definitionSource instanceof RegExpBasedFilterInvocationDefinitionMap) {
    247 
    248 return ((RegExpBasedFilterInvocationDefinitionMap) definitionSource).getAttributes(object);
    249 
    250 }else if(definitionSource instanceof PathBasedFilterInvocationDefinitionMap) {
    251 
    252 return ((PathBasedFilterInvocationDefinitionMap) definitionSource).getAttributes(object);
    253 
    254 }
    255 
    256 throw new IllegalStateException("wrong type of " + definitionSource + ", it should be " + RegExpBasedFilterInvocationDefinitionMap.class
    257 + " or " + PathBasedFilterInvocationDefinitionMap.class);
    258 
    259 }
    260 
    261 public Iterator getConfigAttributeDefinitions() {
    262 
    263 initMap();
    264 
    265 if (definitionSource instanceof RegExpBasedFilterInvocationDefinitionMap) {
    266 
    267 return ((RegExpBasedFilterInvocationDefinitionMap) definitionSource).getConfigAttributeDefinitions();
    268 
    269 }else if(definitionSource instanceof PathBasedFilterInvocationDefinitionMap) {
    270 
    271 return ((PathBasedFilterInvocationDefinitionMap) definitionSource).getConfigAttributeDefinitions();
    272 
    273 }
    274 
    275 throw new IllegalStateException("wrong type of " + definitionSource + ", it should be " + RegExpBasedFilterInvocationDefinitionMap.class
    276 + " or " + PathBasedFilterInvocationDefinitionMap.class);
    277 
    278 }
    279 
    280 public boolean supports(Class clazz) {
    281 
    282 initMap();
    283 
    284 if (definitionSource instanceof RegExpBasedFilterInvocationDefinitionMap) {
    285 
    286 return ((RegExpBasedFilterInvocationDefinitionMap) definitionSource).supports(clazz);
    287 
    288 }else if(definitionSource instanceof PathBasedFilterInvocationDefinitionMap) {
    289 
    290 return ((PathBasedFilterInvocationDefinitionMap) definitionSource).supports(clazz);
    291 
    292 }
    293 
    294 throw new IllegalStateException("wrong type of " + definitionSource + ", it should be " + RegExpBasedFilterInvocationDefinitionMap.class
    295 + " or " + PathBasedFilterInvocationDefinitionMap.class);
    296 
    297 }
    298 
    299 public String getResourceExpression() {
    300 
    301 return resourceExpression;
    302 
    303 }
    304 
    305 public void setResourceExpression(String resourceExpression) {
    306 
    307 this.resourceExpression = resourceExpression;
    308 
    309 }
    310 
    311 public boolean isConvertUrlToLowercaseBeforeComparison() {
    312 
    313 return convertUrlToLowercaseBeforeComparison;
    314 
    315 }
    316 
    317 public void setConvertUrlToLowercaseBeforeComparison(
    318 
    319 boolean convertUrlToLowercaseBeforeComparison) {
    320 
    321 this.convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
    322 
    323 }
    324 
    325 }
    326 


    修改spring配置, 使用我們新建立的類和對應的SQL:

     1 <bean id="filterInvocationInterceptor"
     2 class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
     3 
     4 <property name="authenticationManager"
     5 ref="authenticationManager" />
     6 
     7 <property name="accessDecisionManager">
     8 
     9 <bean class="org.acegisecurity.vote.AffirmativeBased">
    10 
    11 <property name="allowIfAllAbstainDecisions"
    12 value="false" />
    13 
    14 <property name="decisionVoters">
    15 
    16 <list>
    17 
    18 <bean class="org.acegisecurity.vote.RoleVoter" />
    19 
    20 <bean
    21 
    22 class="org.acegisecurity.vote.AuthenticatedVoter" />
    23 
    24 </list>
    25 
    26 </property>
    27 
    28 </bean>
    29 
    30 </property>
    31 
    32 <property name="objectDefinitionSource">
    33 
    34 <ref bean="rolePermissionService"/>
    35 
    36 </property>
    37 
    38 </bean>
    39 
    40 <bean id="rolePermissionService"
    41 class="org.security.acegi.AcegiJdbcDefinitionSourceImpl">
    42 
    43 <property name="dataSource">
    44 
    45 <ref bean="dataSource" />
    46 
    47 </property>
    48 
    49 <property name="permissionsQuery">
    50 
    51 <value>
    52 
    53 SELECT resource_name, role_name FROM resource_role rr, resource re, role ro
    54 
    55 WHERE rr.role_id = ro.role_id and rr.resource_id = re.resource_id
    56 
    57 </value>
    58 
    59 </property>
    60 
    61 <property name="convertUrlToLowercaseBeforeComparison" value="false"></property>
    62 
    63 <property name="resourceExpression" value="PATTERN_TYPE_APACHE_ANT"></property>
    64 
    65 </bean>

    2.3 使用JUnit進行測試

    AcegiPermissionTestCase.java

    package org.security;
    import java.io.IOException;
    import java.util.Iterator;
    import java.util.LinkedHashMap;
    import java.util.Map;
    import java.util.Set;
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import org.acegisecurity.AccessDeniedException;
    import org.acegisecurity.Authentication;
    import org.acegisecurity.ConfigAttributeDefinition;
    import org.acegisecurity.GrantedAuthority;
    import org.acegisecurity.GrantedAuthorityImpl;
    import org.acegisecurity.intercept.web.FilterInvocation;
    import org.acegisecurity.intercept.web.FilterInvocationDefinitionSource;
    import org.acegisecurity.intercept.web.FilterSecurityInterceptor;
    import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.mock.web.MockHttpServletRequest;
    import org.springframework.mock.web.MockHttpServletResponse;
    import org.security.BaseSpringTestCase;
    import org.security.IResourceRole;
    import org.security.IUserDetails;
    import org.security.ResourceRoleImpl;
    import org.security.acegi.AcegiJdbcDaoImpl;
    /** * * The class <code>AcegiPermissionTestCase</code> test acegi permission settings<br><br> * $log$<br><br> * @author $Author: wade $ * @version $Revision: 1.0 $ * @see */ public class AcegiPermissionTestCase extends BaseSpringTestCase {
    @Autowired
    private FilterInvocationDefinitionSource objectDefinitionSource;
    @Autowired
    private AcegiJdbcDaoImpl userDetailsService;
    @Autowired
    private FilterSecurityInterceptor filterInvocationInterceptor;
    /** * Get Authentication Token by username * @param username * @return Authentication */ protected Authentication getAuthentication(String username){
    IUserDetails userDetail = userDetailsService.loadUserByUsername(username);
    Authentication authenticated;
    if(userDetail.isEnabled()){
    authenticated = new UsernamePasswordAuthenticationToken(userDetail, username, userDetail.getAuthorities());
    }else{
    // authenticated = new AnonymousAuthenticationToken(username, userDetail, userDetail.getAuthorities()); authenticated = new UsernamePasswordAuthenticationToken(null, null, new GrantedAuthority[]{new GrantedAuthorityImpl("ROLE_ANONYMOUS")});
    }
    return authenticated;
    }
    /** * get FilterInvocation from the url * @param url * @return FilterInvocation */ protected FilterInvocation getRequestedResource(String url){
    MockHttpServletRequest request = new MockHttpServletRequest();
    request.setServletPath(url);
    MockHttpServletResponse response = new MockHttpServletResponse();
    FilterChain filterchain = new FilterChain(){
    public void doFilter(ServletRequest arg0, ServletResponse arg1)
    throws IOException, ServletException {
    }};
    FilterInvocation object = new FilterInvocation(request, response, filterchain);
    return object;
    }
    /** * throws AccessDeniedException if no permission * @param username * @param uri */ public void checkPermission(boolean shouldHasPermission, String username, String url){
    Authentication authenticated = getAuthentication(username);
    FilterInvocation object = getRequestedResource(url);
    ConfigAttributeDefinition attr = objectDefinitionSource.getAttributes(object);
    boolean hasPermission = false;
    try{
    filterInvocationInterceptor.getAccessDecisionManager().decide(authenticated, object, attr);
    hasPermission = true;
    }catch(AccessDeniedException e){
    hasPermission = false;
    }
    if(hasPermission){
    assertTrue(username + " shouldn't be able to access " + url, shouldHasPermission);
    }else{
    assertFalse(username + " should be able to access " + url, shouldHasPermission);
    }
    }
    public void testPermissionForAdmin(){
    Map<IResourceRole, Boolean> map = new LinkedHashMap<IResourceRole, Boolean>();
    map.put(new ResourceRoleImpl("/admin/index.jsp", "admin" ), true);
    map.put(new ResourceRoleImpl("/admin/index.jsp", "project" ), false);
    map.put(new ResourceRoleImpl("/admin/index.jsp", "dev" ), false);
    map.put(new ResourceRoleImpl("/admin/index.jsp", "disabled" ), false);
    map.put(new ResourceRoleImpl("/admin", "admin" ), true);
    map.put(new ResourceRoleImpl("/admin", "project"), false);
    map.put(new ResourceRoleImpl("/admin", "dev" ), false);
    map.put(new ResourceRoleImpl("/admin", "disabled"), false);
    map.put(new ResourceRoleImpl("/project/index.jsp", "admin" ), true);
    map.put(new ResourceRoleImpl("/project/index.jsp", "project"), true);
    map.put(new ResourceRoleImpl("/project/index.jsp", "dev" ), false);
    map.put(new ResourceRoleImpl("/project/index.jsp", "disabled"), false);
    map.put(new ResourceRoleImpl("/project", "admin" ), true);
    map.put(new ResourceRoleImpl("/project", "project" ), true);
    map.put(new ResourceRoleImpl("/project", "dev" ), false);
    map.put(new ResourceRoleImpl("/project", "disabled" ), false);
    map.put(new ResourceRoleImpl("/developer/index.jsp", "admin" ), true);
    map.put(new ResourceRoleImpl("/developer/index.jsp", "project" ), true);
    map.put(new ResourceRoleImpl("/developer/index.jsp", "dev" ), true);
    map.put(new ResourceRoleImpl("/developer/index.jsp", "disabled" ), false);
    map.put(new ResourceRoleImpl("/developer", "admin" ), true);
    map.put(new ResourceRoleImpl("/developer", "project" ), true);
    map.put(new ResourceRoleImpl("/developer", "dev" ), true);
    map.put(new ResourceRoleImpl("/developer", "disabled" ), false);
    map.put(new ResourceRoleImpl("/index.jsp", "admin" ), true);
    map.put(new ResourceRoleImpl("/index.jsp", "project"), true);
    map.put(new ResourceRoleImpl("/index.jsp", "dev" ), true);
    map.put(new ResourceRoleImpl("/index.jsp", "disabled"), true);
    map.put(new ResourceRoleImpl("/acegilogin.jsp", "admin" ), true);
    map.put(new ResourceRoleImpl("/acegilogin.jsp", "project" ), true);
    map.put(new ResourceRoleImpl("/acegilogin.jsp", "dev" ), true);
    map.put(new ResourceRoleImpl("/acegilogin.jsp", "disabled" ), true);
    Set<IResourceRole> keySet= map.keySet();
    Iterator<IResourceRole> ita = keySet.iterator();
    while(ita != null && ita.hasNext()){
    IResourceRole resourceRole = ita.next();
    boolean expectedPermission = map.get(resourceRole);
    checkPermission(expectedPermission, resourceRole.getRole(), resourceRole.getResource());
    }
    }
    }

    三. 集成之后

    3.1 更改數據庫中的權限

    到目前為止, 一切順利, 但是有一個問題, 用戶如何修改權限, 修改后我們寫的類如何能知道權限變了, 需要去重新加載呢? 看來我們需要再加一些代碼以便于在權限被修改后能夠得到消息, 然后去刷新權限.

    為此, 我們使用Observe(觀察者) 模式, 在改變權限后, 由改變權限的類通過調用PermissionEventPublisher.update(this.getClass())發出消息說權限變了.

    IPermissionListener.java

    public interface IPermissionListener {
    public void updatePermission(Class eventSource);
    }

    PermissionEventPublisher.java

     1 package org.security.event;
     2 
     3 import java.util.HashMap;
     4 
     5 import java.util.Iterator;
     6 
     7 import java.util.Map;
     8 
     9 import org.apache.commons.logging.Log;
    10 
    11 import org.apache.commons.logging.LogFactory;
    12 
    13 /**
    14  * The class PermissionEventPublisher provides a way to notify the IPermissionListener that the permission has been changed.
    15  * @author wade
    16  *
    17  */
    18 public class PermissionEventPublisher {
    19 
    20 private static Log logger = LogFactory.getLog(PermissionEventPublisher.class);
    21 
    22 private static Map<IPermissionListener, IPermissionListener> observerList =
    23 
    24 new HashMap<IPermissionListener, IPermissionListener>();
    25 
    26 /**
    27      * Attach a listener for permission event
    28      * 
    29      * @param subject
    30      * @param listener
    31      */
    32 public static void attach(IPermissionListener listener){
    33 
    34 observerList.put(listener, listener);
    35 
    36 if(logger.isDebugEnabled()){
    37 
    38 logger.debug("Added listener: " + listener.getClass().getName());
    39 
    40 }
    41 
    42 }
    43 
    44 /**
    45      * Detatch from the event updater
    46      * @param listener
    47      */
    48 public static void detatch(IPermissionListener listener){
    49 
    50 observerList.remove(listener);
    51 
    52 if(logger.isDebugEnabled()){
    53 
    54 logger.debug("Removeded listener: " + listener.getClass().getName());
    55 
    56 }
    57 
    58 }
    59 
    60 /**
    61      * send message to each listener.
    62      * @param eventSource
    63      */
    64 public static void update(Class eventSource){
    65 
    66 if(logger.isDebugEnabled()){
    67 
    68 logger.debug("permission changed from "+eventSource.getName());
    69 
    70 }
    71 
    72 Iterator<IPermissionListener> ita = observerList.keySet().iterator();
    73 
    74 while(ita.hasNext()){
    75 
    76 IPermissionListener permissionListener = ita.next();
    77 
    78 permissionListener.updatePermission(eventSource);
    79 
    80 if(logger.isDebugEnabled()){
    81 
    82 logger.debug("call update for listener=" + permissionListener.getClass().getName());
    83 
    84 }
    85 
    86 }
    87 
    88 }
    89 
    90 }

    修改AcegiJdbcDefinitionSourceImpl.java, 增加updatePermission方法, 在權限變化后進行處理

     1 public class AcegiJdbcDefinitionSourceImpl extends JdbcDaoSupport implements
     2 
     3 InitializingBean, FilterInvocationDefinitionSource, IPermissionListener {
     4 
     5 public AcegiJdbcDefinitionSourceImpl() {
     6 
     7 permissionsQuery = DEF_PERMISSIONS_QUERY;
     8 
     9 //attach to event publisher, so the class can get the notify when permission changes
    10 PermissionEventPublisher.attach(this);
    11 
    12 }
    13 
    14 /**
    15      * Set definitionSource to null, so we can get a refreshed permission list from db
    16      */
    17 public void updatePermission(Class eventSource) {
    18 
    19 definitionSource = null;
    20 
    21 }
    22 
    23 }


    3.2 在程序中獲取當前用戶

    直接從Acegi中取用戶信息不太方便, 為了簡化獲取用戶的方法, 可以添加一個類封裝對應的邏輯, 然后通過CurrentUser.getUser()直接取到用戶信息.

    CurrentUser.java

     1 /**
     2      * Get current user which stored in session
     3      * You must set a user when using junit test
     4      * @return IUserDetails
     5      */
     6 public static IUserDetails getUser(){
     7 
     8 //if not in unit test environment, get the current user using acegi
     9 if ((SecurityContextHolder.getContext() == null)
    10 
    11 || !(SecurityContextHolder.getContext() instanceof SecurityContext)
    12 
    13 || (((SecurityContext) SecurityContextHolder.getContext())
    14 
    15 .getAuthentication() == null)) {
    16 
    17 return null;
    18 
    19 }
    20 
    21 Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    22 
    23 if (auth.getPrincipal() == null) {
    24 
    25 return null;
    26 
    27 }
    28 
    29 IUserDetails user = null;
    30 
    31 if (auth.getPrincipal() instanceof IUserDetails) {
    32 
    33 user = (IUserDetails)auth.getPrincipal();
    34 
    35 }
    36 
    37 return user;
    38 
    39 }
    40 


    3.3 使用Tag來判斷用戶是否具有某一種Role的權限

    有一點一定要注意, 由于Filter的處理有順序,所以需要將Acegi的Filter放在最前面.

    <authz:authorize ifAnyGranted="ROLE_SUPERVISOR, ROLE_ADMINISTRATOR, ROLE_FULLACCESS">

    Role in ROLE_SUPERVISOR, ROLE_ADMINISTRATOR, ROLE_FULLACCESS

    </authz:authorize>

    3.4 添加自己的Tag

    Acegi 提供的Tag只能判斷當前用戶是不是具有某種Role, 不能判斷當前用戶對某一個URL有沒有權限, 由于很多時候需要根據當前用戶的權限來控制某些功能是否顯示, 比如只有管理員才顯示Add或Delete按鈕

    這是你可以自己寫自己的Tag, 為了簡單起見, 我們繼承jstl的Tag, 比如下面實現兩個條件的Tag, Tag的用法如下:

    <auth:ifNotAuthrized url="/system/acl.action">如果當前用戶沒有指定url的權限,顯示本部分內容</auth:ifNotAuthrized>

    <auth:ifAuthrized url="/system/acl.action">如果當前用戶有指定url的權限,顯示本部分內容</auth:ifAuthrized>

    AuthorizedTag.java

      1 public class AuthorizedTag extends ConditionalTagSupport {
      2 
      3 protected Log logger = LogFactory.getLog(this.getClass());
      4 
      5 @Autowired
      6 
      7 private FilterInvocationDefinitionSource objectDefinitionSource;
      8 
      9 @Autowired
     10 
     11 private FilterSecurityInterceptor filterInvocationInterceptor;
     12 
     13 private String url;
     14 
     15 /**
     16      * Get Authentication Token from  IUserDetails object
     17      * @param user
     18      * @return Authentication
     19      */
     20 protected Authentication getAuthentication(IUserDetails user){
     21 
     22 IUserDetails userDetail = user;
     23 
     24 Authentication authenticated;
     25 
     26 if(userDetail == null){
     27 
     28 authenticated = new UsernamePasswordAuthenticationToken(nullnullnew GrantedAuthority[]{new GrantedAuthorityImpl("ROLE_ANONYMOUS")});
     29 
     30 }else{
     31 
     32 if(userDetail.isEnabled()){
     33 
     34 authenticated = new UsernamePasswordAuthenticationToken(userDetail, userDetail.getUsername(), userDetail.getAuthorities());
     35 
     36 }else{
     37 
     38 authenticated = new AnonymousAuthenticationToken(userDetail.getUsername(), userDetail, userDetail.getAuthorities());
     39 
     40 }
     41 
     42 }
     43 
     44 return authenticated;
     45 
     46 }
     47 
     48 /**
     49      * get FilterInvocation from the url 
     50      * @param url
     51      * @return FilterInvocation
     52      */
     53 protected FilterInvocation getRequestedResource(String url){
     54 
     55 MockHttpServletRequest request = new MockHttpServletRequest(pageContext.getServletContext());
     56 
     57 request.setServletPath(url);
     58 
     59 FilterChain filterchain = new FilterChain(){
     60 
     61 public void doFilter(ServletRequest arg0, ServletResponse arg1)
     62 
     63 throws IOException, ServletException {
     64 
     65 }};
     66 
     67 FilterInvocation object = new FilterInvocation(request, pageContext.getResponse(), filterchain);
     68 
     69 return object;
     70 
     71 }
     72 
     73 @Override
     74 
     75 protected boolean condition() throws JspTagException {
     76 
     77 boolean result = false;
     78 
     79 IUserDetails user = CurrentUser.getUser();
     80 
     81 ServletContext servletContext = pageContext.getServletContext();
     82 
     83 WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
     84 
     85 wac.getAutowireCapableBeanFactory().autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false);
     86 
     87 ConfigAttributeDefinition attr = objectDefinitionSource.getAttributes(getRequestedResource(url));
     88 
     89 try{
     90 
     91 filterInvocationInterceptor.getAccessDecisionManager().decide(getAuthentication(user), url, attr);
     92 
     93 result = true;
     94 
     95 }catch(AccessDeniedException e){
     96 
     97 result = false;
     98 
     99 if(user == null){
    100 
    101 logger.debug("anonymous has no permission on :" + url);
    102 
    103 }else{
    104 
    105 logger.debug(user.getUsername() + " has no permission on :" + url);
    106 
    107 }
    108 
    109 }
    110 
    111 return result;
    112 
    113 }
    114 
    115 public String getUrl() {
    116 
    117 return url;
    118 
    119 }
    120 
    121 public void setUrl(String url) {
    122 
    123 this.url = url;
    124 
    125 }
    126 
    127 }

    添加Jsp頁面測試新添加的Tag, 在文所附的例子程序中, 將Tag的測試代碼放在index.jsp頁面中, 任何人都可以訪問該頁面, 在頁面上列出了全部地址的鏈接, 同時列出了當前用戶有權限的地址, 這樣可以方便地知道當前用戶有哪些權限, 如果你想修改數據庫中的權限, 然后再次測試, 可以點擊頁面右上側的Reload Permission重新從數據庫加載權限.

    <auth:ifAuthrized url="/admin">
    <p><a href="admin">Admin page</a></p>
    </auth:ifAuthrized>
    

    四. 參考文檔

    1. 更多深入介紹,可以根據Acegi官方提供的Suggested Steps (http://www.acegisecurity.org/suggested.html) 一步一步學習.

    2. 如果要了解Acegi提供的各種功能, 可以參考http://www.acegisecurity.org/reference.html

    3. 閱讀本文需要對Spring有一定的了解, http://www.springframework.org/documentation

    4. 擴展jstl的tag, 可以參看http://www.onjava.com/pub/a/onjava/2002/10/30/jstl3.html?page=1

    5. 從https://sourceforge.net/project/platformdownload.php?group_id=216220下載本文附帶的例子代碼, 通過acegi.sql建立數據庫, 然后將acegi-test.war放到Tomcat的webapps目錄下, 或者你可以下載acegi-test.zip文件, 里面包含了完整的eclipse的項目以及sql文件.

    訪問http://youip:port/acegi-test, 列出全部地址的鏈接, 同時列出了當前用戶有權限的地址鏈接


    轉自:http://acegi-test.sourceforge.net/


    主站蜘蛛池模板: 亚洲系列国产精品制服丝袜第| 亚洲网红精品大秀在线观看| 精品亚洲A∨无码一区二区三区| 亚洲三级在线视频| 在线播放国产不卡免费视频| 最近免费中文字幕大全高清大全1| 四虎成人免费网址在线| 亚洲韩国精品无码一区二区三区| 亚洲三级高清免费| 中国videos性高清免费| 成人性生交视频免费观看| 国精无码欧精品亚洲一区| 亚洲国产成人AV在线播放| 国产高清不卡免费视频| 免费人成在线观看网站视频| 久久久久亚洲AV无码专区首JN| 黄色一级毛片免费| 野花高清在线观看免费完整版中文| 亚洲综合区小说区激情区| 精品日韩99亚洲的在线发布| 可以免费观看的毛片| 免费国产成人高清视频网站| 亚洲人成影院77777| 两个人看的www高清免费视频| 免费毛片在线视频| 亚洲精品在线网站| 中文字幕无码免费久久9一区9| 免费看大美女大黄大色| 亚洲视频精品在线观看| 岛国岛国免费V片在线观看| 日韩人妻无码免费视频一区二区三区 | 亚洲综合久久1区2区3区| 永久免费无码网站在线观看个| 久久久久久久免费视频| 亚洲av永久无码精品国产精品| 无码天堂va亚洲va在线va| 国产免费不卡视频| 无码专区—VA亚洲V天堂| 国产99久久久国产精免费| 四虎影视永久免费视频观看| 亚洲天堂免费在线|