2024年4月2日发(作者:)

Spring Security 3.0 安全权限管理手册

参考文献:

1、中的spring security权限管理手册。

2、spring security3.0权限管理手册

3、spring的相关资料。

本文档内容仅仅作为公司权限管理资料用,对于企业来说,权限管理将是系

统中的非常重要的一个模块,权限的设计也是参考相关资料进行整理和补充。系

统将通过数据库进行管理用户权限。

权限管理搭建要的问题:

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

配置,应用安全过滤器

配置Spring,验证与授权部分

在web页面中获取用户身份

在web页面中应用安全标签库

实现方法级安全

6、配置

7、Spring配置文件中设置命名空间

8、通过数据库验证用户身份

9、完善web页面验证规则

10、自定义验证配置

11、本地化消息输出(国际化)

根据公司项目的开发要求和集合spring security3.0功能,公司将通过数

据库进行对用户身份验证和授权,系统将建立5个基础表进行对权利的管理。

第一部分 数据库设计

1、表设计

表1:用户表(pub_users)

序号 字段

1 User_Id

2 user_account

3

4

5

6

7

类型

Vchar(32)

Vchar(30)

User_name Vchar(40)

user_Password Vchar(100)

Enabled Int 0禁用1正常

是否是超级用户

isSys Int 0非1是

描述

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表中描述的是系统按用户分类或按照功能模块分类,将系统进

含义

用户id

登陆用户名

(登陆号)

用户姓名

用户密码

是否被禁用

备注

PK

行整合归类管理。

表4:资源表(pub_resources)

序号 字段 类型 含义 备注

1 resource_Id Vchar(32) 资源id PK

2 resource_name Vchar(100) 资源名称

3 resource

_type

Vchar(40) 资源类型 url、method

priority

4 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、配置

webAppRootKey

rstframe

xmlns:xsi="/2001/XMLSchema-instance"

xsi:schemaLocation="/xml/ns/javaee

/xml/ns/javaee/web-app_2_">

log4jConfigLocation

classpath:ties

log4jRefreshInterval

60000

contextConfigLocation

classpath*:/,

classpath*:/

encodingFilter

terEncodingFilter

encoding

UTF-8

encodingFilter

/*

ssionInViewFilter

excludeSuffixs

js,css,jpg,gif

hibernateOpenSessionInViewFilter

hibernateOpenSessionInViewFilter

/*

springSecurityFilterChain

tingFilterProxy

ilter-class>

springSecurityFilterChain

/*

PrepareAndExecuteFi

struts2Filter

lter

struts2Filter

/*

tLoaderListener

4jConfigListener

pectorCleanupListener

r

ble

/common/

20

ssionEventPublishe

500

/common/

404

/common/

403

/common/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

/WEB-INF/

/WEB-INF/tlds/

rar

application/rar

5、配置spring security3.0中的xml文件

文件名:

xmlns:beans="/schema/beans"

xmlns:xsi="/2001/XMLSchema-instance"

xsi:schemaLocation="/schema/beans

/schema/beans/

/schema/security

/schema/security/

d">

SpringSecurity安全配置

default-target-url="/"

error-if-maximum-exceeded="true" />

before="FILTER_SECURITY_INTERCEPTOR"/>

class="erSecurityInter

ceptor">

ref="authenticationManager" />

ref="myAccessDecisionManagerBean" />

ref="mySecurityMetadataSource" />

class="ssDecisionManager">

class="cationSecurityMetad

ataSourceService">

class="ableResourceBundleMe

ssageSource">

user-service-ref="userDetailsService">

class="DetailService" />

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

第三部分 SS3.0的实现

这是项目的主体部分:

这四个类说明如下。

一、用来获得用户验证信息(

MyUserDetailService)

代码如下:

package t;

import ist;

import tion;

import ;

import red;

import cessException;

import dAuthority;

import ;

import

tails;

import

tailsService;

import

meNotFoundExc

eption;

import e;

import

horitiesResourcesDao;

import rsDao;

import horities;

import

horitiesResources;

//你就可以从数据库中读入用户的密码,角色信息,是否锁定,账号是否过期

@Service

public class MyUserDetailService implements UserDetailsService

{

@Autowired

private PubUsersDao pubUsersDao;

@Autowired

private

throws

Collection

//取得用户的权限

List

String password=null;

//取得用户的密码

auths=new

UsernameNotFoundException,

PubAuthoritiesResourcesDao

pubAuthoritiesResourcesDao;

public UserDetails loadUserByUsername(String username)

DataAccessException {

ArrayList();

auth=thByUserName(username);

password=erByname(username).get(0).getUserPa

List

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

ssword();

aaa=();

User user = new User(username,

return user;

}

}

二、最核心的地方,就是提供某个资源对应的权限定义,取得所有角色(auth)

的对应资源数据(

MyInvocationSecurityMetadataSourceService)

代码如下:

package t;

import ist;

import tion;

import p;

import or;

import ;

import ;

import tContext;

import ;

import n;

import nFactory;

import

red;

import ationContext;

import

athXmlApplicationContex

t;

import Attribute;

import tyConfig;

import Invocation;

import

Invocatio

nSecurityMetadataSource;

import

PathMatcher;

import cher;

import e;

import ateDao;

import

horitiesResourcesDao;

import horities;

import ources;

/*

*

* 最核心的地方,就是提供某个资源对应的权限定义,即

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>

resourceMap = null;

public MyInvocationSecurityMetadataSourceService() {

loadResourceDefine();

}

/* private void loadResourceDefine() {

resourceMap = new HashMap

Collection>();

Collection atts = new

ArrayList();

ConfigAttribute ca = new

SecurityConfig("ROLE_ADMIN");

(ca);

("/", atts);

("/", atts);

}*/

private void loadResourceDefine() {

ApplicationContext context = new

ClassPathXmlApplicationContext("");

SessionFactory sessionFactory =

(SessionFactory)n("sessionFactory");

Session session = ssion();

List query=SQLQuery("select

authority_name from pub_authorities ").list();

resourceMap = new HashMap

Collection>();

Collection atts = new

ArrayList();

//List auths =Query(arg0);

//thAll();

for (String auth : query) {

ConfigAttribute ca = new SecurityConfig(auth);//

"ROLE_ADMIN"

// (ca);

List query1=SQLQuery("select

resource_string " +

"from Pub_Authorities_Resources,Pub_Resources,

Pub_authorities " +

"where

Pub_Authorities_ce_id=Pub_ce_id

and " +

"

Pub_Authorities_ce_id=Pub_ity_i

d and " +

" Authority_name='"+auth+"'").list();

for (String res : query1) {

String url = res;

// 判断资源文件和权限的对应关系,如果已经存在,要

进行增加

if (nsKey(url)) {

Collection value =

(url);

(ca);

(url, value);

// "","role_user,role_admin"

} else {

(ca);

(url, atts);

}

(url, atts);

}

}

}

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

this URL.

public Collection getAttributes(Object

object)

throws IllegalArgumentException {

// guess object is a URL.

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

Iterator ite = ().iterator();

while (t()) {

String resURL = ();

if (tchesUrl(url, resURL)) {

return (resURL);

}

}

return null;

}

public boolean supports(Class clazz) {

return true;

}

public Collection getAllConfigAttributes()

{

return null;

}

}

三、最重要的是decide方法,如果不存在对该资源的定义,直接放行;否则,

如果找到正确的角色,即认为拥有权限,并放行,否则throw new

AccessDeniedException("no right");这样,就会进入上面提到的

页面。(

MyAccessDecisionManager

)

代码如下:

package t;

import tion;

import or;

import DecisionManager;

import DeniedException;

import Attribute;

import tyConfig;

import

icientAuthenticationExce

ption;

import tication;

import dAuthority;

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 configAttributes)

throws AccessDeniedException,

InsufficientAuthenticationException {

if(configAttributes == null){

return ;

}

n(ng()); //object is a URL.

Iterator ite=or();

while(t()){

ConfigAttribute ca=();

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

for(GrantedAuthority ga:horities()){

if((hority())){ //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 = Invocation(fi);这一句,

即在执行doFilter之前,进行权限的检查,而具体的实现已经交给

accessDecisionManager了(

MyFilterSecurityInterceptor

)

代码如下:

package eptor;

import ption;

import ;

import Chain;

import Config;

import tException;

import tRequest;

import tResponse;

import red;

import DecisionManager;

import tyMetadataSource;

import

ctSecurityInterce

ptor;

import

eptorStatusToken;

import Invocation;

import

InvocationSec

urityMetadataSource;

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 tyMetadataSource;

}

public Class getSecureObjectClass() {

return ;

}

public void invoke(FilterInvocation fi) throws IOException,

ServletException {

InterceptorStatusToken token = Invocation(fi);

try {

in().doFilter(uest(), ponse());

} finally {

nvocation(token, null);

}

}

@Override

public SecurityMetadataSource obtainSecurityMetadataSource() {

return tyMetadataSource;

}

public void setSecurityMetadataSource(

FilterInvocationSecurityMetadataSource

securityMetadataSource) {

n("abc=======================edf");

tyMetadataSource = securityMetadataSource;

}

public void destroy() {

// TODO Auto-generated method stub

}

public void init(FilterConfig filterconfig) throws ServletException

{

// TODO Auto-generated method stub

}

}

如有异议,请加qq:89168934,互相学习交流。