Jsp Spring Security 权限管理系统

简介:

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,如需转载请自行联系原作者

相关文章
|
9月前
|
JSON 安全 Java
什么是JWT?如何使用Spring Boot Security实现它?
什么是JWT?如何使用Spring Boot Security实现它?
1671 5
|
4月前
|
人工智能 安全 Java
spring boot 权限管理的几种方式
Spring Boot 提供多种权限管理方式,包括基于角色的访问控制(RBAC)、基于属性的访问控制(ABAC)和基于访问控制列表(ACL)。RBAC 通过角色简化权限管理;ABAC 根据用户、资源和环境属性实现细粒度控制;ACL 则为每个资源定义访问控制列表。文中以 Spring Security 为例,详细展示了每种方法的配置与实现步骤,帮助开发者根据项目需求选择合适的权限管理方案。示例涵盖依赖添加、类配置及注解使用等关键环节。
591 0
|
5月前
|
存储 Java 数据库
Spring Boot 注册登录系统:问题总结与优化实践
在Spring Boot开发中,注册登录模块常面临数据库设计、密码加密、权限配置及用户体验等问题。本文以便利店销售系统为例,详细解析四大类问题:数据库字段约束(如默认值缺失)、密码加密(明文存储风险)、Spring Security配置(路径权限不当)以及表单交互(数据丢失与提示不足)。通过优化数据库结构、引入BCrypt加密、完善安全配置和改进用户交互,提供了一套全面的解决方案,助力开发者构建更 robust 的系统。
159 0
|
2月前
|
存储 人工智能 自然语言处理
用Spring AI搭建本地RAG系统:让AI成为你的私人文档助手
想让AI帮你读懂PDF文档吗?本文教你用Spring AI和Ollama搭建一个本地RAG系统,让AI成为你的私人文档助手。无需GPU,无需云端API,只需几行代码,你的文档就能开口说话了!
|
消息中间件 存储 Java
📨 Spring Boot 3 整合 MQ 构建聊天消息存储系统
本文详细介绍了如何使用Spring Boot 3结合RabbitMQ构建高效可靠的聊天消息存储系统。通过引入消息队列,实现了聊天功能与消息存储的解耦,解决了高并发场景下直接写入数据库带来的性能瓶颈问题。文章首先分析了不同MQ产品的特点及适用场景,最终选择RabbitMQ作为解决方案,因其成熟稳定、灵活路由和易于集成等优势。接着,通过Docker快速部署RabbitMQ,并完成Spring Boot项目的配置与代码实现,包括生产者发送消息、消费者接收并处理消息等功能。最后,通过异步存储机制,既保证了消息的即时性,又实现了可靠持久化。
341 0
📨 Spring Boot 3 整合 MQ 构建聊天消息存储系统
|
5月前
|
存储 人工智能 Java
Spring AI与DeepSeek实战四:系统API调用
在AI应用开发中,工具调用是增强大模型能力的核心技术,通过让模型与外部API或工具交互,可实现实时信息检索(如天气查询、新闻获取)、系统操作(如创建任务、发送邮件)等功能;本文结合Spring AI与大模型,演示如何通过Tool Calling实现系统API调用,同时处理多轮对话中的会话记忆。
982 57
|
3月前
|
Java 调度 流计算
基于Java 17 + Spring Boot 3.2 + Flink 1.18的智慧实验室管理系统核心代码
这是一套基于Java 17、Spring Boot 3.2和Flink 1.18开发的智慧实验室管理系统核心代码。系统涵盖多协议设备接入(支持OPC UA、MQTT等12种工业协议)、实时异常检测(Flink流处理引擎实现设备状态监控)、强化学习调度(Q-Learning算法优化资源分配)、三维可视化(JavaFX与WebGL渲染实验室空间)、微服务架构(Spring Cloud构建分布式体系)及数据湖建设(Spark构建实验室数据仓库)。实际应用中,该系统显著提升了设备调度效率(响应时间从46分钟降至9秒)、设备利用率(从41%提升至89%),并大幅减少实验准备时间和维护成本。
234 0
|
6月前
|
人工智能 自然语言处理 Java
对话即服务:Spring Boot整合MCP让你的CRUD系统秒变AI助手
本文介绍了如何通过Model Context Protocol (MCP) 协议将传统Spring Boot服务改造为支持AI交互的智能系统。MCP作为“万能适配器”,让AI以统一方式与多种服务和数据源交互,降低开发复杂度。文章以图书管理服务为例,详细说明了引入依赖、配置MCP服务器、改造服务方法(注解方式或函数Bean方式)及接口测试的全流程。最终实现用户通过自然语言查询数据库的功能,展示了MCP在简化AI集成、提升系统易用性方面的价值。未来,“对话即服务”有望成为主流开发范式。
4923 7
|
6月前
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot中的全局异常处理——处理系统异常
本文介绍了在Spring Boot项目中如何通过创建`GlobalExceptionHandler`类来全局处理系统异常。通过使用`@ControllerAdvice`注解,可以拦截项目中的各种异常,并结合`@ExceptionHandler`注解针对特定异常(如参数缺失、空指针等)进行定制化处理。文中详细展示了处理参数缺失异常和空指针异常的示例代码,并说明了通过拦截`Exception`父类实现统一异常处理的方法。虽然拦截`Exception`可一劳永逸,但为便于问题排查,建议优先处理常见异常,最后再兜底处理未知异常,确保返回给调用方的信息友好且明确。
704 0
微服务——SpringBoot使用归纳——Spring Boot中的全局异常处理——处理系统异常
|
8月前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
527 8