您的位置:首页 > 编程语言 > Java开发

spring security总结 太有用了!!

2015-09-09 10:03 525 查看
转至: http://www.cnblogs.com/yl2755/archive/2012/04/19/2456823.html
谢谢作者!!!

首先导入spring security所需要的jar包

spring-security-core-2.0.5.RELEASE.jar

spring-security-core-tiger-2.0.5.RELEASE.jar

一.配置过滤器

在web.xml中定义如下过滤器

springSecurityFilterChain

org.springframework.web.filter.DelegatingFilterProxy

springSecurityFilterChain

CREATE TABLE `t_account` (

`id` int(11) NOT
NULL,

`username` varchar(255) default
NULL,

`password` varchar(255) default
NULL,

`enabled` int default NULL,

PRIMARY KEY
(`id`)

)
ENGINE=InnoDB DEFAULT
CHARSET=utf8;

CREATE TABLE
`t_role` (

`id` int(11) NOT
NULL,

`name` varchar(255) default NULL,

`descn` varchar(255) default NULL,

PRIMARY KEY
(`id`)

) ENGINE=InnoDB DEFAULT
CHARSET=utf8;

CREATE TABLE `t_account_role` (

`a_id` int(11) NOT
NULL,

`r_id` int(11) NOT
NULL,

PRIMARY KEY
(`a_id`,`r_id`),

KEY `FK1C2BC9332D31C656`
(`r_id`),

KEY `FK1C2BC93371CCC630`
(`a_id`),

CONSTRAINT `FK1C2BC93384B0A30E` FOREIGN KEY
(`a_id`) REFERENCES `t_account`
(`id`),

CONSTRAINT `FK1C2BC9332D31C656` FOREIGN KEY
(`r_id`) REFERENCES `t_role`
(`id`)

) ENGINE=InnoDB DEFAULT
CHARSET=utf8;

insert into t_account
values(1,'zhangsan','123',1);

insert into t_account
values(2,'lisi','321',1);

insert into t_role
values(1,'系统管理员','ROLE_ADMIN');

insert into t_role
values(2,'普通用户','ROLE_USER');

insert into t_account_role
values(1,2);

insert into
t_account_role values(2,1);

当用户登录时,spring security首先判断用户是否可以登录。用户登录后spring
security获得该用户的

所有权限以判断用户是否可以访问资源。

spring配置文件中定义

users-by-username-query="select username,password,enabled from
t_account where username=?"

authorities-by-username-query="select r.descn from t_account_role
ar join

t_account a on ar.a_id=a.id join t_role r on ar.r_id=r.id where
a.username=?"/>

users-by-username-query:根据用户名查找用户

authorities-by-username-query:根据用户名查找这个用户所有的角色名,将用户访问的URL地址和

查询结果与标签进行匹配。

匹配成功就允许访问,否则就返回到提示页面。


在标签中添加登录页面等信息

CREATE TABLE `t_account` (

`id` int(11) NOT
NULL,

`username` varchar(255) default
NULL,

`password` varchar(255) default
NULL,

`enabled` int default NULL,

PRIMARY KEY
(`id`)

)
ENGINE=InnoDB DEFAULT
CHARSET=utf8;

CREATE TABLE
`t_role` (

`id` int(11) NOT
NULL,

`name` varchar(255) default NULL,

`descn` varchar(255) default NULL,

PRIMARY KEY
(`id`)

) ENGINE=InnoDB DEFAULT
CHARSET=utf8;

CREATE TABLE `t_account_role` (

`a_id` int(11) NOT
NULL,

`r_id` int(11) NOT
NULL,

PRIMARY KEY
(`a_id`,`r_id`),

KEY `FK1C2BC9332D31C656`
(`r_id`),

KEY `FK1C2BC93371CCC630`
(`a_id`),

CONSTRAINT `FK1C2BC93384B0A30E` FOREIGN KEY
(`a_id`) REFERENCES `t_account`
(`id`),

CONSTRAINT `FK1C2BC9332D31C656` FOREIGN KEY
(`r_id`) REFERENCES `t_role`
(`id`)

) ENGINE=InnoDB DEFAULT
CHARSET=utf8;

CREATE TABLE `t_module` (

`id` int(11) NOT
NULL,

`name` varchar(255) default
NULL,

`address` varchar(255) default
NULL,

PRIMARY KEY
(`id`)

) ENGINE=InnoDB DEFAULT
CHARSET=utf8;

CREATE TABLE `t_module_role` (

`m_id` int(11) NOT
NULL,

`r_id` int(11) NOT
NULL,

PRIMARY KEY
(`m_id`,`r_id`),

KEY `FKA713071E2D31C656`
(`r_id`),

KEY `FKA713071ED78C9071`
(`m_id`),

CONSTRAINT `FKA713071ED78C9071` FOREIGN KEY
(`m_id`) REFERENCES `t_module`
(`id`),

CONSTRAINT `FKA713071E2D31C656` FOREIGN KEY
(`r_id`) REFERENCES `t_role`
(`id`)

) ENGINE=InnoDB DEFAULT
CHARSET=utf8;

insert into t_account
values(1,'zhangsan','123',1);

insert into t_account
values(2,'lisi','321',1);

insert into t_role
values(1,'系统管理员','ROLE_ADMIN');

insert into t_role
values(2,'普通用户','ROLE_USER');

insert into t_account_role
values(1,2);

insert into
t_account_role values(2,1);

insert into
t_module
values(1,'部门管理','/dept.jsp');

insert into
t_module
values(2,'人员管理','/emp.jsp');

insert into
`t_module_role` values(1,1);

insert into
`t_module_role` values(1,2);

insert into
`t_module_role` values(2,1);

1.在自定义的过滤器中获取资源的URL地址和角色名以取代spring配置文件中原有的

过滤器代码:

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.LinkedHashMap;

import java.util.List;

import java.util.Map;

import javax.sql.DataSource;

import
org.springframework.beans.factory.FactoryBean;

import
org.springframework.jdbc.core.support.JdbcDaoSupport;

import
org.springframework.jdbc.object.MappingSqlQuery;

import
org.springframework.security.ConfigAttributeDefinition;

import
org.springframework.security.ConfigAttributeEditor;

import
org.springframework.security.intercept.web.DefaultFilterInvocationDefinitionSource;

import
org.springframework.security.intercept.web.FilterInvocationDefinitionSource;

import
org.springframework.security.intercept.web.RequestKey;

import
org.springframework.security.util.AntUrlPathMatcher;

import
org.springframework.security.util.UrlMatcher;

public class
JdbcFilterInvocationDefinitionSourceFactoryBean

extends
JdbcDaoSupport implements FactoryBean
{

private
String resourceQuery;

public
boolean isSingleton() {

return true;

}

public Class
getObjectType() {

return
FilterInvocationDefinitionSource.class;

}

public
Object getObject() {

return new
DefaultFilterInvocationDefinitionSource(this

.getUrlMatcher(),
this.buildRequestMap());

}

protected
Map findResources() {

ResourceMapping resourceMapping = new
ResourceMapping(getDataSource(),

resourceQuery);

Map resourceMap = new
LinkedHashMap();

for (Resource resource : (List) resourceMapping.execute())
{

String url = resource.getUrl();

String role =
resource.getRole();

if (resourceMap.containsKey(url))
{

String value =
resourceMap.get(url);

resourceMap.put(url, value + "," +
role);

} else {

resourceMap.put(url, role);

}

}

return resourceMap;

}

protected
LinkedHashMap buildRequestMap()
{

LinkedHashMap requestMap = null;

requestMap = new
LinkedHashMap();

ConfigAttributeEditor editor = new
ConfigAttributeEditor();

Map resourceMap =
this.findResources();

for (Map.Entry entry : resourceMap.entrySet())
{

RequestKey key = new RequestKey(entry.getKey(),
null);

editor.setAsText(entry.getValue());

requestMap.put(key,

(ConfigAttributeDefinition)
editor.getValue());

}

return requestMap;

}

protected
UrlMatcher getUrlMatcher() {

return new AntUrlPathMatcher();

}

public void
setResourceQuery(String resourceQuery)
{

this.resourceQuery =
resourceQuery;

}

private
class Resource {

private String url;

private String role;

public Resource(String url, String role)
{

this.url = url;

this.role = role;

}

public String getUrl() {

return url;

}

public String getRole() {

return role;

}

}

private
class ResourceMapping extends MappingSqlQuery
{

protected ResourceMapping(DataSource
dataSource,

String resourceQuery) {

super(dataSource,
resourceQuery);

compile();

}

protected Object mapRow(ResultSet rs, int
rownum)

throws SQLException {

String url = rs.getString(1);

String role = rs.getString(2);

Resource resource = new Resource(url,
role);

return resource;

}

}

}

将自定义的过滤器放入到原有的spring
security过滤器链中(在spring配置文件中配置)

定义自定义过滤器(sql语句用于查询资源的URL地址 如:/index.jsp 和角色名
如ROLE_USER)

class="com.lovo.JdbcFilterInvocationDefinitionSourceFactoryBean">

select m.address,r.descn

from t_module_role mr

join t_module m on mr.m_id=m.id

join t_role r on mr.r_id=r.id;

"/>

将自定义过滤器放入过滤器链中

class="org.springframework.security.intercept.web.FilterSecurityInterceptor"
>

注意:FilterSecurityInterceptor过滤器会向request中写入一个标记,用于标记是否已经控制了当前请求,以避免对同一请求多次处理,导致第2个FilterSecurityInterceptor不会再次执行。

在中不需要再定义,如下:

authentication-failure-url="/error.jsp"

default-target-url="/index.jsp"
/>

自定义的过滤器就从配置文件中读取sql,查询结果就是角色和资源,用户登录时就在session中保存了用户的角色。

注意:intercept-url的先后顺序,spring
security使用第一个能匹配的intercept-url标签进行权限控制。

现在intercept-url来源于数据库,所以在sql查询时注意角色和资源的顺序。

建议在角色和资源的中间表中添加1个字段用于标识顺序,(按从严到宽的顺序)

表结构修改如下:

CREATE TABLE `t_module_role` (

`m_id` int(11) NOT
NULL,

`r_id` int(11) NOT
NULL,

`priority` int(11) default NULL,

PRIMARY KEY
(`m_id`,`r_id`),

KEY `FKA713071E2D31C656`
(`r_id`),

KEY `FKA713071ED78C9071`
(`m_id`),

CONSTRAINT `FKA713071ED78C9071` FOREIGN KEY
(`m_id`) REFERENCES `t_module`
(`id`),

CONSTRAINT `FKA713071E2D31C656` FOREIGN KEY
(`r_id`) REFERENCES `t_role`
(`id`)

) ENGINE=InnoDB DEFAULT
CHARSET=utf8;

数据如下:

insert into t_account
values(1,'zhangsan','123',1);

insert into t_account
values(2,'lisi','321',1);

insert into t_role
values(1,'系统管理员','ROLE_ADMIN');

insert into t_role
values(2,'普通用户','ROLE_USER');

insert into t_account_role
values(1,2);

insert into
t_account_role values(2,1);

insert into
t_module
values(1,'部门管理','/dept.jsp');

insert into
t_module
values(2,'人员管理','/emp.jsp');

insert into
`t_module_role` values(1,1,3);

insert into
`t_module_role` values(1,2,2);

insert into
`t_module_role` values(2,1,1);

自定义过滤器修改如下:

class="com.lovo.JdbcFilterInvocationDefinitionSourceFactoryBean">

select m.address,r.descn

from t_module_role mr

join t_module m on mr.m_id=m.id

join t_role r on mr.r_id=r.id

order by mr.priority

"/>

如果持久层使用的是hibernate,那么只需要给自定义过滤器注入1个hibernateTemplate.

在自定义过滤器中就不需要再使用mapRow的方式。而是直接获取url和角色名即可。

例如:

public class
ModuleFilter implements FactoryBean
{

private String resourceQuery;

public
boolean isSingleton() {

return true;

}

public Class
getObjectType() {

return
FilterInvocationDefinitionSource.class;

}

public
Object getObject() {

return new
DefaultFilterInvocationDefinitionSource(this

.getUrlMatcher(),
this.buildRequestMap());

}

protected
Map findResources() {

ResourceMapping resourceMapping = new
ResourceMapping();

Map resourceMap = new
LinkedHashMap();

for (Resource resource : (List) resourceMapping.execute())
{

String url = resource.getUrl();

String role =
resource.getRole();

if (resourceMap.containsKey(url))
{

String value =
resourceMap.get(url);

resourceMap.put(url, value + "," +
role);

} else {

resourceMap.put(url, role);

}

}

return resourceMap;

}

protected
LinkedHashMap buildRequestMap()
{

LinkedHashMap requestMap = null;

requestMap = new
LinkedHashMap();

ConfigAttributeEditor editor = new
ConfigAttributeEditor();

Map resourceMap =
this.findResources();

for (Map.Entry entry : resourceMap.entrySet())
{

RequestKey key = new RequestKey(entry.getKey(),
null);

editor.setAsText(entry.getValue());

requestMap.put(key,

(ConfigAttributeDefinition)
editor.getValue());

}

return requestMap;

}

protected
UrlMatcher getUrlMatcher() {

return new AntUrlPathMatcher();

}

public void
setResourceQuery(String resourceQuery)
{

this.resourceQuery =
resourceQuery;

}

private
class Resource {

private String url;

private String role;

public Resource(String url, String role)
{

this.url = url;

this.role = role;

}

public String getUrl() {

return url;

}

public String getRole() {

return role;

}

}

private
class ResourceMapping{

public List execute(){

List rlist = new ArrayList();

List list =
hibernateTemplate.find(resourceQuery);

for(int i=0;i

Role role = list.get(i);

Set set = role.getModuleSet();

Iterator it = set.iterator();

while(it.hasNext()){

Module m = it.next();

Resource re = new
Resource(m.getUrl(),role.getDescn());

rlist.add(re);

}

}

return rlist;

}

}

public void
setHibernateTemplate(HibernateTemplate hibernateTemplate)
{

this.hibernateTemplate =
hibernateTemplate;

}

private HibernateTemplate
hibernateTemplate;

}

而从灵活性的角度考虑,把hql写在配置文件中

value="from com.lovo.po.Role order by
ind">

问题:系统只会在初始化的时候从数据库中加载信息。无法识别数据库中信息的改变。

解决:每个jsp页面上重新内存

代码:每个jsp页面include如下代码:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: