JspSpringSecurity許可權管理系統

範大腳腳發表於2017-11-21

Jsp Spring Security 許可權管理系統 

許可權管理搭建要的問題:

1、區分Authentication(驗證)與 Authorization(授權)

驗證

這個使用者是誰?

使用者身份可靠嗎?

授權

某使用者A是否可以訪問資源R

某使用者A是否可以執行M操作

某使用者A是否可以對資源R執行M操作

2、SS中的驗證特點

支援多種驗證方式

支援多種加密格式

支援元件的擴充套件和替換

可以本地化輸出資訊

3、SS中的授權特點

支援多種仲裁方式

支援元件的擴充套件和替換

支援對頁面訪問、方法訪問、物件訪問的授權。

4、SS核心安全實現

Web安全

通過配置Servlet Filter啟用SS中的過濾器鏈

實現Session一致性驗證

實現免登陸驗證(Remember-Me驗證)

提供一系列標籤庫進行頁面元素的安全控制

方法安全

通過AOP模式實現安全代理

Web安全與方法安全均可以使用表示式語言定義訪問規則

5、配置SS

配置Web.xml,應用安全過濾器

配置Spring,驗證與授權部分

在web頁面中獲取使用者身份

在web頁面中應用安全標籤庫

實現方法級安全

6、配置web.xml

7、Spring配置檔案中設定名稱空間

8、通過資料庫驗證使用者身份

9、完善web頁面驗證規則

10、自定義驗證配置

11、本地化訊息輸出(國際化)

    

根據公司專案的開發要求和集合spring security3.0功能,公司將通過資料庫進行對使用者身份驗證和授權,系統將建立5個基礎表進行對權利的管理。

 

第一部分 資料庫設計

1、表設計

表1:使用者表(pub_users)

序號

欄位

型別

含義

備註

1

User_Id

Vchar(32)

使用者id

PK

2

user_account

Vchar(30)

登陸使用者名稱(登陸號)

 

3

User_name

Vchar(40)

使用者姓名

 

4

user_Password

Vchar(100)

使用者密碼

 

5

Enabled

Int

是否被禁用

0禁用1正常

6

isSys

Int

是否是超級使用者

0非1是

7

user_DESc

Vchar(100)

描述

 

說明:pub_users表中的登入名和密碼用來控制使用者的登入。

表2:許可權表(pub_authorities)

序號

欄位

型別

含義

備註

1

authority_Id

Vchar(32)

許可權id

PK

2

Authority_name

Vchar(40)

許可權名稱

 

3

Authority_DESc

Vchar(100)

許可權描述

 

4

Enabled

Int

是否被禁用

0禁用1正常

5

isSys

Int

是否是超級許可權

0非1是

說明:pub_authorities表中描述的是系統擁有哪些許可權,如果要詳細分類,可以將一個url定義一個許可權,那樣就能對所有資源進行管理。

表3:角色表(pub_roles)

序號

欄位

型別

含義

備註

1

role_Id

Vchar(32)

角色id

PK

2

role_name

Vchar(100)

角色名稱

 

3

role_DESc

Vchar(100)

角色描述

 

4

Enabled

Int

是否被禁用

0禁用1正常

5

isSys

Int

是否是超級許可權

0非1是

說明:pub_roles表中描述的是系統按使用者分類或按照功能模組分類,將系統進行整合歸類管理。

表4:資源表(pub_resources)

序號

欄位

型別

含義

備註

1

resource_Id

Vchar(32)

資源id

PK

2

resource_name

Vchar(100)

資源名稱

 

3

resource _type

Vchar(40)

資源型別

url、method

4

priority

int

資源優先權

即排序

5

resource _string

Vchar(200)

資源連結

 

6

resource_DESc

Vchar(100)

資源描述

 

7

Enabled

Int

是否被禁用

0禁用1正常

8

isSys

Int

是否是超級許可權

0非1是

說明:pub_roles表中描述的是系統需要保護的資源及(url或方法)。

以上四個表是許可權管理的基礎表(使用者表、許可權表、角色表、資源表)。

 

表5:使用者角色連線表(pub_users_roles)

序號

欄位

型別

含義

備註

1

Id

Indetity

Id主鍵

PK

2

user_Id

Vchar(32)

使用者id

 

3

role_id

Vchar(32)

角色id

 

說明:用來管理使用者和角色的關係。

表6:角色許可權連線表(pub_roles_authorities)

序號

欄位

型別

含義

備註

1

Id

Indetity

Id主鍵

PK

2

role _Id

Vchar(32)

角色id

 

3

authority_Id

Vchar(32)

許可權id

 

說明:用來管理角色和許可權的關係。

表7:許可權資源連線表(pub_authorities_resources)

序號

欄位

型別

含義

備註

1

Id

Indetity

Id主鍵

PK

2

authority_Id

Vchar(32)

許可權id

 

3

resource_Id

Vchar(32)

資源id

 

說明:用來管理角色和許可權的關係。

2、建表語句如下(資料庫採用MS SQL 2000):

create table pub_users(

    user_id varchar(32),

 user_account varchar(30),

 user_name varchar(40),

 user_password varchar(100),

 user_desc varchar(100),

 enabled int,

 issys int

);

alter table pub_users add constraint pk_pub_users primary key(user_id);

 

create table pub_authorities(

  authority_id varchar(32),

   authority_name varchar(40), 

 authority_desc varchar(100),

 enabled int,

 issys int

);

alter table pub_authorities add constraint pk_pub_authorities primary key(authority_id);

 

create table pub_roles(

  role_id varchar(32),

   role_name varchar(40), 

 role_desc varchar(100),

 enabled int,

 issys int

);

alter table pub_roles add constraint pk_pub_roles primary key(role_id);

 

create table pub_resources(

  resource_id varchar(32),

   resource_name varchar(100), 

 resource_desc varchar(100),

   resource_type varchar(40), 

 resource_string varchar(200),

 priority int,

 enabled int,

 issys int

);

alter table pub_resources add constraint pk_pub_resources primary key(resource_id);

 

create table pub_users_roles(

   id numeric(12,0) IDENTITY NOT NULL, 

   user_id varchar(32), 

 role_id varchar(32),

 enabled int

);

alter table pub_users_roles add constraint pk_pub_users_roles primary key(id);

alter table pub_users_roles add constraint fk_users_roles_users foreign key(user_id) references pub_users(user_id);

alter table pub_users_roles add constraint fk_users_roles_roles foreign key(role_id) references pub_roles(role_id);

 

 

create table pub_roles_authorities(

   id numeric(12,0) IDENTITY NOT NULL, 

 role_id varchar(32),

   authority_id varchar(32), 

 enabled int

);

alter table pub_roles_authorities add constraint pk_pub_roles_authorities primary key(id);

alter table pub_roles_authorities add constraint fk_pub_roles_authorities_authorities foreign key(authority_id) references pub_authorities(authority_id);

alter table pub_roles_authorities add constraint fk_pub_roles_authorities_roles foreign key(role_id) references pub_roles(role_id);

 

create table pub_authorities_resources(

   id numeric(12,0) IDENTITY NOT NULL, 

   authority_id varchar(32), 

 resource_id varchar(32),

 enabled int

);

alter table pub_authorities_resources add constraint pk_pub_authorities_resources primary key(id);

alter table pub_authorities_resources add constraint fk_pub_authorities_resources_authorities foreign key(authority_id) references pub_authorities(authority_id);

alter table pub_authorities_resources add constraint fk_pub_authorities_resources_resources foreign key(resource_id) references pub_resources(resource_id);

 

3、E-R圖如下:

 

 

第二部分 WEB資料庫整合

提示:相關程式碼請參考專案模組

1、將資料庫表結構和Hibernate建立對映,本系統採用annotation進行對資料庫進行零配置處理(請參考hibernate對映),如圖。

 

2、建立許可權的Dao層。

 

3、建立許可權的Service層

 

4、配置web.xml

   <?xml version=”1.0″ encoding=”UTF-8″?>

<web-app version=”2.5″ xmlns=”http://java.sun.com/xml/ns/javaee”

xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”

xsi:schemaLocation=”http://java.sun.com/xml/ns/javaee 

http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd”>

 

<display-name>rstframe</display-name>

 

<context-param>

<param-name>webAppRootKey</param-name>

<param-value>rstframe.root</param-value>

</context-param>

 

<context-param>

<param-name>log4jConfigLocation</param-name>

<param-value>classpath:log4j.properties</param-value>

</context-param>

 

<context-param>

<param-name>log4jRefreshInterval</param-name>

<param-value>60000</param-value>

</context-param>

 

<!– Spring ApplicationContext配置檔案的路徑,可使用萬用字元,多個路徑用,號分隔

此引數用於後面的Spring Context Loader –>

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>

classpath*:/applicationContext.xml,

classpath*:/applicationContext-rstframe.xml

</param-value>

</context-param>

 

<!– Character Encoding filter –>

<filter>

<filter-name>encodingFilter</filter-name>

<filter-class>

org.springframework.web.filter.CharacterEncodingFilter

</filter-class>

<init-param>

<param-name>encoding</param-name>

<param-value>UTF-8</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>encodingFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

 

<!– SpringSide`s Hibernate Open Session In View filter–>

<filter>

<filter-name>hibernateOpenSessionInViewFilter</filter-name>

<filter-class>

com.rstco.frame.modules.orm.hibernate.OpenSessionInViewFilter

</filter-class>

<init-param>

<param-name>excludeSuffixs</param-name>

<param-value>js,css,jpg,gif</param-value>

</init-param>

</filter>

 

<filter-mapping>

<filter-name>hibernateOpenSessionInViewFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

 

<!– SpringSecurity filter–>

    <filter>

        <filter-name>springSecurityFilterChain</filter-name>

        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

    </filter>

    <filter-mapping>

        <filter-name>springSecurityFilterChain</filter-name>

        <url-pattern>/*</url-pattern>

    </filter-mapping>

 

   <!– Struts2 filter, actionPackages –>

<filter>

<filter-name>struts2Filter</filter-name>

<filter-class>

org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

</filter-class>

</filter>

<filter-mapping>

<filter-name>struts2Filter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

  <!–SpringApplicationContext 載入 –>

<listener>

<listener-class>

org.springframework.web.context.ContextLoaderListener

</listener-class>

</listener>

<listener>

<listener-class>

org.springframework.web.util.Log4jConfigListener

</listener-class>

</listener>

<!– Spring 重新整理Introspector防止記憶體洩露 –>

<listener>

<listener-class>

org.springframework.web.util.IntrospectorCleanupListener

</listener-class>

</listener>

<!–  防止多人登陸 ,控制一個使用者只能登入一次,不能在其他地方重新登入–>

   <listener>

<listener-class>

org.springframework.security.web.session.HttpSessionEventPublisher 

</listener-class>

</listener>

 

<!– session超時定義,單位為分鐘 –>

<session-config>

<session-timeout>20</session-timeout>

</session-config>

 

<welcome-file-list>

<welcome-file>index.jsp</welcome-file>

</welcome-file-list>

 

<!– error page –>

<error-page>

<exception-type>java.lang.Throwable</exception-type>

<location>/common/500.jsp</location>

</error-page>

<error-page>

<error-code>500</error-code>

<location>/common/500.jsp</location>

</error-page>

<error-page>

<error-code>404</error-code>

<location>/common/404.jsp</location>

</error-page>

<error-page>

<error-code>403</error-code>

<location>/common/403.jsp</location>

</error-page>

 

<jsp-config>

<taglib>

<taglib-uri>/WEB-INF/struts-menu-el.tld</taglib-uri>

<taglib-location>

/WEB-INF/tlds/struts-menu-el.tld

</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/struts-menu.tld</taglib-uri>

<taglib-location>

/WEB-INF/tlds/struts-menu.tld

</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/c.tld</taglib-uri>

<taglib-location>/WEB-INF/tlds/c.tld</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/fmt.tld</taglib-uri>

<taglib-location>/WEB-INF/tlds/fmt.tld</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/fn.tld</taglib-uri>

<taglib-location>/WEB-INF/tlds/fn.tld</taglib-location>

</taglib>

<!–loushang tld–>

<taglib>

<taglib-uri>/WEB-INF/web-date.tld</taglib-uri>

<taglib-location>

/WEB-INF/tlds/web-date.tld

</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/web-flex.tld</taglib-uri>

<taglib-location>

/WEB-INF/tlds/web-flex.tld

</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/web-graph.tld</taglib-uri>

<taglib-location>

/WEB-INF/tlds/web-graph.tld

</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/web-grid.tld</taglib-uri>

<taglib-location>

/WEB-INF/tlds/web-grid.tld

</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/web-html.tld</taglib-uri>

<taglib-location>

/WEB-INF/tlds/web-html.tld

</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/web-list.tld</taglib-uri>

<taglib-location>

/WEB-INF/tlds/web-list.tld

</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/web-loushang.tld</taglib-uri>

<taglib-location>

/WEB-INF/tlds/web-loushang.tld

</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/web-menu.tld</taglib-uri>

<taglib-location>

/WEB-INF/tlds/web-menu.tld

</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/web-multitab.tld</taglib-uri>

<taglib-location>

/WEB-INF/tlds/web-multitab.tld

</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/web-seltree.tld</taglib-uri>

<taglib-location>

/WEB-INF/tlds/web-seltree.tld

</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/web-tab.tld</taglib-uri>

<taglib-location>/WEB-INF/tlds/web-tab.tld</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/web-tree.tld</taglib-uri>

<taglib-location>

/WEB-INF/tlds/web-tree.tld

</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/web-widgets.tld</taglib-uri>

<taglib-location>

/WEB-INF/tlds/web-widgets.tld

</taglib-location>

</taglib>

<taglib>

<taglib-uri>/WEB-INF/web-i18n.tld</taglib-uri>

<taglib-location>

/WEB-INF/tlds/web-i18n.tld

</taglib-location>

</taglib>

<!– loushang end –>

<taglib>

<taglib-uri>/WEB-INF/gystudio.tld</taglib-uri>

<taglib-location>

/WEB-INF/tlds/gystudio.tld

</taglib-location>

</taglib>

</jsp-config>

 

<mime-mapping>

<extension>rar</extension>

<mime-type>application/rar</mime-type>

</mime-mapping>

 

</web-app>

5、配置spring security3.0中的xml檔案

   檔名:applicationContext-security.xml

<?xml version=”1.0″ encoding=”UTF-8″?>

<beans:beans xmlns=”http://www.springframework.org/schema/security”

    xmlns:beans=”http://www.springframework.org/schema/beans”

    xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”

    xsi:schemaLocation=”http://www.springframework.org/schema/beans

           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

           http://www.springframework.org/schema/security

           http://www.springframework.org/schema/security/spring-security-3.0.xsd”>

 

<beans:description>SpringSecurity安全配置</beans:description>

 

<!– http安全配置 –>

   <http auto-config=”true”>

<intercept-url pattern=”/css/**” filters=”none” />

<intercept-url pattern=”/images/**” filters=”none” />

<intercept-url pattern=”/js/**” filters=”none” />

<intercept-url pattern=”/login.jsp” filters=”none” />

<!–

<intercept-url pattern=”/index.jsp”  access=”ROLE_USER”/>

<intercept-url pattern=”/main.jsp”  access=”ROLE_ADAMIN”/>

    –>

<form-login login-page=”/login.jsp” default-target-url=”/index.jsp”

 authentication-failure-url=”/login.jsp?error=1″ />

<!– 嘗試訪問沒有許可權的頁面時跳轉的頁面 –>   

<access-denied-handler error-page=”/common/403.jsp”/> 

 

<logout logout-success-url=”/login.jsp” />

 

 <session-management>

         <concurrency-control max-sessions=”1″ error-if-maximum-exceeded=”true” />

     </session-management>

 

<!– 增加一個filter,這點與Acegi是不一樣的,不能修改預設的filter了,

這個filter位於FILTER_SECURITY_INTERCEPTOR之前  –>

         <custom-filter ref=”myFilter” before=”FILTER_SECURITY_INTERCEPTOR”/>

       

 </http>

 

<!– 一個自定義的filter,必須包含authenticationManager,accessDecisionManager,securityMetadataSource三個屬性,

     我們的所有控制將在這三個類中實現,解釋詳見具體配置  –>

    <beans:bean id=”myFilter” class=”com.rstco.frame.pub.security.interceptor.MyFilterSecurityInterceptor”>

        <beans:property name=”authenticationManager”

            ref=”authenticationManager” />

        <beans:property name=”accessDecisionManager”

            ref=”myAccessDecisionManagerBean” />

        <beans:property name=”securityMetadataSource”

            ref=”mySecurityMetadataSource” />

    </beans:bean>

   

<!– 驗證配置 , 認證管理器,實現使用者認證的入口,主要實現UserDetailsService介面即可 –>

  <authentication-manager alias=”authenticationManager”> 

   

<authentication-provider user-service-ref=”userDetailsService”>

   <!–

<s:password-encoder hash=”sha” />

 –>

</authentication-provider>

 

</authentication-manager>

 

<!– 專案實現的使用者查詢服務,將使用者資訊查詢出來  –>

<beans:bean id=”userDetailsService” class=”com.rstco.frame.pub.security.support.MyUserDetailService” />

 

<!– 訪問決策器,決定某個使用者具有的角色,是否有足夠的許可權去訪問某個資源     –>

    <beans:bean id=”myAccessDecisionManagerBean”

        class=”com.rstco.frame.pub.security.support.MyAccessDecisionManager”>

    </beans:bean>

 

    <!– 資源源資料定義,將所有的資源和許可權對應關係建立起來,即定義某一資源可以被哪些角色訪問  –>

    <beans:bean id=”mySecurityMetadataSource”

        class=”com.rstco.frame.pub.security.support.MyInvocationSecurityMetadataSourceService”>

    </beans:bean>

    

      

    <!– 定義國際化 –>

    <beans:bean id=”messageSource”

     class=”org.springframework.context.support.ReloadableResourceBundleMessageSource”>

   <beans:property name=”basename” 

    value=”classpath:org/springframework/security/messages_zh_CN”/>

</beans:bean>

</beans:beans>

 

 

第三部分 SS3.0的實現

這是專案的主體部分:

 

這四個類說明如下。

一、 用來獲得使用者驗證資訊(MyUserDetailService)

程式碼如下:

package com.rstco.frame.pub.security.support;

 

import java.util.ArrayList;

import java.util.Collection;

import java.util.List;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.dao.DataAccessException;

import org.springframework.security.core.GrantedAuthority;

import org.springframework.security.core.userdetails.User;

import org.springframework.security.core.userdetails.UserDetails;

import org.springframework.security.core.userdetails.UserDetailsService;

import org.springframework.security.core.userdetails.UsernameNotFoundException;

import org.springframework.stereotype.Service;

 

import com.rstco.frame.pub.security.dao.PubAuthoritiesResourcesDao;

import com.rstco.frame.pub.security.dao.PubUsersDao;

import com.rstco.frame.pub.security.entity.PubAuthorities;

import com.rstco.frame.pub.security.entity.PubAuthoritiesResources;

 

//你就可以從資料庫中讀入使用者的密碼,角色資訊,是否鎖定,賬號是否過期

@Service

public class MyUserDetailService implements UserDetailsService  {

@Autowired

private PubUsersDao pubUsersDao;

@Autowired

private PubAuthoritiesResourcesDao pubAuthoritiesResourcesDao;

 

public UserDetails loadUserByUsername(String username)

throws UsernameNotFoundException, DataAccessException {

 

Collection<GrantedAuthority> auths=new ArrayList<GrantedAuthority>();

//取得使用者的許可權

List<PubAuthorities> auth=pubUsersDao.findAuthByUserName(username);

String password=null;

//取得使用者的密碼

password=pubUsersDao.findUserByname(username).get(0).getUserPassword();

 

List<PubAuthoritiesResources> aaa=pubAuthoritiesResourcesDao.getAll();

 

        User user = new User(username,

         password, true, true, true, true, auths);

        

        return user;

}

 

}

二、 最核心的地方,就是提供某個資源對應的許可權定義,取得所有角色(auth)的對應資源資料(MyInvocationSecurityMetadataSourceService)

程式碼如下: 

package com.rstco.frame.pub.security.support;

 

import java.util.ArrayList;

import java.util.Collection;

import java.util.HashMap;

import java.util.Iterator;

import java.util.List;

import java.util.Map;

 

import javax.servlet.ServletContext;

 

import org.hibernate.Query;

import org.hibernate.Session;

import org.hibernate.SessionFactory;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import org.springframework.security.access.ConfigAttribute;

import org.springframework.security.access.SecurityConfig;

import org.springframework.security.web.FilterInvocation;

import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;

import org.springframework.security.web.util.AntUrlPathMatcher;

import org.springframework.security.web.util.UrlMatcher;

import org.springframework.stereotype.Service;

 

import com.rstco.frame.modules.orm.hibernate.HibernateDao;

import com.rstco.frame.pub.security.dao.PubAuthoritiesResourcesDao;

import com.rstco.frame.pub.security.entity.PubAuthorities;

import com.rstco.frame.pub.security.entity.PubResources;

 

/*

 * 

 * 最核心的地方,就是提供某個資源對應的許可權定義,即getAttributes方法返回的結果。

 * 注意,我例子中使用的是AntUrlPathMatcher這個path matcher來檢查URL是否與資源定義匹配,

 * 事實上你還要用正則的方式來匹配,或者自己實現一個matcher。

 * 

 * 此類在初始化時,應該取到所有資源及其對應角色的定義

 * 

 * 說明:對於方法的spring注入,只能在方法和成員變數裡注入,

 * 如果一個類要進行例項化的時候,不能注入物件和操作物件,

 * 所以在建構函式裡不能進行操作注入的資料。

 */

@Service

public class MyInvocationSecurityMetadataSourceService  implements

FilterInvocationSecurityMetadataSource {

 

    @Autowired

private PubAuthoritiesResourcesDao pubAuthoritiesResourcesDao;

 

private UrlMatcher urlMatcher = new AntUrlPathMatcher();

private static Map<String, Collection<ConfigAttribute>> resourceMap = null;

 

public MyInvocationSecurityMetadataSourceService() {

loadResourceDefine();

}

 

/*    private void loadResourceDefine() {

        resourceMap = new HashMap<String, Collection<ConfigAttribute>>();

        Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();

        ConfigAttribute ca = new SecurityConfig(“ROLE_ADMIN”);

        atts.add(ca);

        resourceMap.put(“/index.jsp”, atts);

        resourceMap.put(“/i.jsp”, atts);

    }*/

 

private void loadResourceDefine() {

ApplicationContext context = new ClassPathXmlApplicationContext(“applicationContext.xml”);

SessionFactory sessionFactory = (SessionFactory)context.getBean(“sessionFactory”);

 

Session session = sessionFactory.openSession();

List<String> query=session.createSQLQuery(“select authority_name from pub_authorities “).list();

 

 

resourceMap = new HashMap<String, Collection<ConfigAttribute>>();

Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();

 

//List<PubAuthorities> auths =session.createQuery(arg0); //pubAuthoritiesResourcesDao.findAuthAll();

 

for (String auth : query) {

ConfigAttribute ca = new SecurityConfig(auth);// “ROLE_ADMIN”

// atts.add(ca);

 

List<String> query1=session.createSQLQuery(“select resource_string ” +

“from Pub_Authorities_Resources,Pub_Resources,  Pub_authorities ” +

“where Pub_Authorities_Resources.resource_id=Pub_Resources.resource_id and ” +

” Pub_Authorities_Resources.resource_id=Pub_authorities.authority_id  and ” +

”   Authority_name=`”+auth+”`”).list();

 

for (String res : query1) {

String url = res;

// 判斷資原始檔和許可權的對應關係,如果已經存在,要進行增加

if (resourceMap.containsKey(url)) {

Collection<ConfigAttribute> value = resourceMap.get(url);

value.add(ca);

resourceMap.put(url, value);

// “log.jsp”,”role_user,role_admin”

} else {

atts.add(ca);

resourceMap.put(url, atts);

}

 resourceMap.put(url, atts);

}

}

}

 

// According to a URL, Find out permission configuration of this URL.

public Collection<ConfigAttribute> getAttributes(Object object)

throws IllegalArgumentException {

// guess object is a URL.

String url = ((FilterInvocation) object).getRequestUrl();

Iterator<String> ite = resourceMap.keySet().iterator();

while (ite.hasNext()) {

String resURL = ite.next();

if (urlMatcher.pathMatchesUrl(url, resURL)) {

return resourceMap.get(resURL);

}

}

return null;

}

 

public boolean supports(Class<?> clazz) {

return true;

}

public Collection<ConfigAttribute> getAllConfigAttributes() {

return null;

}

}

三、 最重要的是decide方法,如果不存在對該資源的定義,直接放行;否則,如果找到正確的角色,即認為擁有許可權,並放行,否則throw new AccessDeniedException(“no right”);這樣,就會進入上面提到的403.jsp頁面。(MyAccessDecisionManager)

程式碼如下:

 

package com.rstco.frame.pub.security.support;

 

import java.util.Collection;

import java.util.Iterator;

import org.springframework.security.access.AccessDecisionManager;

import org.springframework.security.access.AccessDeniedException;

import org.springframework.security.access.ConfigAttribute;

import org.springframework.security.access.SecurityConfig;

import org.springframework.security.authentication.InsufficientAuthenticationException;

import org.springframework.security.core.Authentication;

import org.springframework.security.core.GrantedAuthority;

 

 

public class MyAccessDecisionManager implements AccessDecisionManager {

 

    //In this method, need to compare authentication with configAttributes.

    // 1, A object is a URL, a filter was find permission configuration by this URL, and pass to here.

    // 2, Check authentication has attribute in permission configuration (configAttributes)

    // 3, If not match corresponding authentication, throw a AccessDeniedException.

    public void decide(Authentication authentication, Object object,

            Collection<ConfigAttribute> configAttributes)

            throws AccessDeniedException, InsufficientAuthenticationException {

        if(configAttributes == null){

            return ;

        }

        System.out.println(object.toString());  //object is a URL.

        Iterator<ConfigAttribute> ite=configAttributes.iterator();

        while(ite.hasNext()){

            ConfigAttribute ca=ite.next();

            String needRole=((SecurityConfig)ca).getAttribute();

            for(GrantedAuthority ga:authentication.getAuthorities()){

                if(needRole.equals(ga.getAuthority())){  //ga is user`s role.

                    return;

                }

            }

        }

        throw new AccessDeniedException(“no right”);

    }

 

    public boolean supports(ConfigAttribute attribute) {

        // TODO Auto-generated method stub

        return true;

    }

 

    public boolean supports(Class<?> clazz) {

        return true;

    }

 

 

}

四、 這個過濾器要插入到授權之前。最核心的程式碼就是invoke方法中的InterceptorStatusToken token = super.beforeInvocation(fi);這一句,即在執行doFilter之前,進行許可權的檢查,而具體的實現已經交給accessDecisionManager了(MyFilterSecurityInterceptor)

程式碼如下:

package com.rstco.frame.pub.security.interceptor;

 

import java.io.IOException;

 

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.security.access.AccessDecisionManager;

import org.springframework.security.access.SecurityMetadataSource;

import org.springframework.security.access.intercept.AbstractSecurityInterceptor;

import org.springframework.security.access.intercept.InterceptorStatusToken;

import org.springframework.security.web.FilterInvocation;

import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;

 

public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor

implements Filter {

 

private FilterInvocationSecurityMetadataSource securityMetadataSource;

 

public void doFilter(ServletRequest request, ServletResponse response,

FilterChain chain) throws IOException, ServletException {

FilterInvocation fi = new FilterInvocation(request, response, chain);

invoke(fi);

}

 

public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {

return this.securityMetadataSource;

}

public Class<? extends Object> getSecureObjectClass() {

return FilterInvocation.class;

}

public void invoke(FilterInvocation fi) throws IOException,

ServletException {

InterceptorStatusToken token = super.beforeInvocation(fi);

try {

fi.getChain().doFilter(fi.getRequest(), fi.getResponse());

} finally {

super.afterInvocation(token, null);

}

}

@Override

public SecurityMetadataSource obtainSecurityMetadataSource() {

return this.securityMetadataSource;

}

 

public void setSecurityMetadataSource(

FilterInvocationSecurityMetadataSource securityMetadataSource) {

System.out.println(“abc=======================edf”);

this.securityMetadataSource = securityMetadataSource;

}

public void destroy() {

// TODO Auto-generated method stub

 

}

public void init(FilterConfig filterconfig) throws ServletException {

// TODO Auto-generated method stub

}

}

本文轉自農夫山泉別墅部落格園部落格,原文連結:http://www.cnblogs.com/yaowen/archive/2013/03/28/2985852.html,如需轉載請自行聯絡原作者


相關文章