完整代码见附件

1. 需要在spring-security.xml中配置验证过滤器,来取代spring-security.xml的默认过滤器

spring-security中需要配置验证过滤器来实现整个拦截的过程,其中需要配置一下三个来实现。

authenticationManager:在配置用户名和角色的时候,已经配置过了。 security:authentication-manager

accessDecisionManager:用来判断url是否有权限

securityMetadataSource:可以通过url得到角色名称

<!-- 配置 验证过滤器, 此过滤器取代系统的XML权限过滤 , 此过滤器配置完毕之后存放到 系统缺省的过滤链中-->
<bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<!-- 需要认证管理器, 通过它可以获取 管理员已经拥有的角色信息 ,
由于id已经被org.springframework.security.authenticationManager默认了。不能更改,所以用别名-->
<property name="authenticationManager" ref="authenticationManager"></property>
<!-- 决策器 -->
<property name="accessDecisionManager" ref="roleAccessDecisionManager" />
<!-- 配置urlService ,security可以通过url得到角色名称 -->
<property name="securityMetadataSource" ref="urlService" />
</bean>

2. 配置securityMetadataSource,可以通过url来获取角色名称

package com.hp.service.impl;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set; import javax.annotation.Resource; import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Service; import com.hp.dao.UrlDao;
import com.hp.model.Role;
import com.hp.model.Url;
import com.hp.service.UrlService; /**
* 通过URL地址获取相应权限然后在获取相应的角色集合
*
* 需要实现FilterInvocationSecurityMetadataSource接口
*
* @author baojulin
*
*/
@Service("urlService")
public class UrlServiceImpl implements UrlService, FilterInvocationSecurityMetadataSource { @Resource
private UrlDao urlDao; @Override
public Url getRoleByUrl(String url) {
return urlDao.getRoleByUrl(url);
} /**
* 此方法就是通过url地址获取 角色信息的方法
*/
@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
// 获取当前的URL地址
System.out.println("object的类型为:" + object.getClass());
FilterInvocation filterInvocation = (FilterInvocation) object;
String url = filterInvocation.getRequestUrl();
System.out.println("访问的URL地址为(包括参数):" + url);
url = filterInvocation.getRequest().getServletPath();
System.out.println("访问的URL地址为:" + url);
Url urlObject = getRoleByUrl(url); //调用自己实现的方法来url
System.out.println("urlObject:" + urlObject);
if (urlObject != null && urlObject.getPrivilege() != null) {
Set<Role> roles = urlObject.getPrivilege().getRoles();
Collection<ConfigAttribute> c = new HashSet<ConfigAttribute>();
c.addAll(roles);
return c; // 将privilege中的roles改为Collection<ConfigAttribute>,role需要实现ConfigAttribute接口
} else {
// 如果返回为null则说明此url地址不需要相应的角色就可以访问, 这样Security会放行
return null;
}
} @Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
// TODO Auto-generated method stub
return null;
} /**
* 如果为真则说明支持当前格式类型,才会到上面的 getAttributes 方法中
*/
@Override
public boolean supports(Class<?> clazz) {
// TODO Auto-generated method stub
// 需要返回true表示支持
return true;
} }

urlDao中的实现

    /**
* 通过URL地址获取相应权限然后在获取相应的角色集合
*/
@Override
public Url getRoleByUrl(String url) {
String hql = "FROM Url u JOIN FETCH u.privilege up JOIN FETCH up.roles WHERE u.url=:url";
Session session = sessionFactory.openSession();
return (Url) session.createQuery(hql).setString("url", url).uniqueResult();
}

3. 配置决策器:roleAccessDecisionManager

package com.hp.service.impl;

import java.util.Collection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service; /**
* 此类是决策器: 用来对 用户应有的角色,与URL地址可以访问的角色进行对比,如果不匹配则抛出异常
*
* @author baojulin
*
*/
@Service("roleAccessDecisionManager")
public class RoleAccessDecisionManager implements AccessDecisionManager { protected final Log logger = LogFactory.getLog(RoleAccessDecisionManager.class); /**
* 决策方法: 如果方法执行完毕没有抛出异常,则说明可以放行, 否则抛出异常 AccessDeniedException
*/
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
// System.out.println("---------------decide------------------");
// 如果登陆成功,则信息会存储在Authorities中
Collection<? extends GrantedAuthority> myRoles = authentication.getAuthorities();
// 如果前面的 getAttributes() 返回非空,则返回的数据做为形参传入, 如果返回为null 则不会进入decide() 直接放行 // System.out.println("myRole:" + myRoles);
// System.out.println("sysRole:" + configAttributes); for (GrantedAuthority myRole : myRoles) {// 当前登录的角色
for (ConfigAttribute urlRoles : configAttributes) {// 前台传入的url的角色,UrlDaoImpl.getAttributes获得的
if (myRole.getAuthority().equals(urlRoles.getAttribute())) {
// 说明此URL地址符合权限,可以放行
return;
}
}
}
// System.out.println("-----权限验证失败------");
logger.error("-----权限验证失败------");
throw new AccessDeniedException("权限越界!");
} /**
* 返回true表示支持
*/
@Override
public boolean supports(ConfigAttribute attribute) {
// System.out.println("public boolean supports(ConfigAttribute attribute)");
return true;
} /**
* 返回true表示支持
*/
@Override
public boolean supports(Class<?> clazz) {
// System.out.println("public boolean supports(Class<?> clazz)");
return true;
} }

4. 在配置文件中,修改默认过滤器,将xml方式配置的权限去掉,改用数据库

    <security:http auto-config="false" use-expressions="true" access-denied-page="/login.jsp?error=access-denied-page">
<!-- xml配置,配置的 pattern="/admin/**" 表示需要登录才能访问,而登录的角色为ROLE_ADMIN
<security:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" />
<security:intercept-url pattern="/user/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')" />
--> <!-- 增加权限过滤器,采用数据库方式获取权限 -->
<security:custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR"/> <!-- 默认登录地址:j_spring_security_check -->
<security:form-login default-target-url="/index.jsp"
username-parameter="username"
password-parameter="password"
authentication-failure-url="/login.jsp?error=authentication-failure-url"
login-page="/login.jsp"/>
<!-- 注销也是由,Security框架来实现,LogoutFilter ,默认地址j_spring_security_logout -->
<security:logout logout-success-url="/login.jsp"/>
</security:http>

5. 图解spring-security整个流程

百度云链接:http://pan.baidu.com/s/1cBTdb4 密码:pjzk

Spring-Security (学习记录四)--配置权限过滤器,采用数据库方式获取权限的更多相关文章

  1. Spring Security 学习记录

    一.核心拦截器详细说明 1.WebAsyncManagerIntegrationFilter 根据请求封装获取WebAsyncManager 从WebAsyncManager获取/注册Security ...

  2. leveldb 学习记录(四)Log文件

    前文记录 leveldb 学习记录(一) skiplistleveldb 学习记录(二) Sliceleveldb 学习记录(三) MemTable 与 Immutable Memtablelevel ...

  3. [转]Spring Security学习总结二

    原文链接: http://www.blogjava.net/redhatlinux/archive/2008/08/20/223148.html http://www.blogjava.net/red ...

  4. [转]Spring Security学习总结一

    [总结-含源码]Spring Security学习总结一(补命名空间配置) Posted on 2008-08-20 10:25 tangtb 阅读(43111) 评论(27)  编辑  收藏 所属分 ...

  5. Spring security 学习 (自助者,天助之!)

    自己努力,何必要强颜欢笑的求助别人呢?  手心向下不求人! Spring security学习有进展哦: 哈哈! 1.页面都是动态生产的吧! 2.设置权限:  a:pom.xml配置jar包 b:cr ...

  6. Spring Security和 JWT两大利器来打造一个简易的权限系统。

    写在前面 关于 Spring Security Web系统的认证和权限模块也算是一个系统的基础设施了,几乎任何的互联网服务都会涉及到这方面的要求.在Java EE领域,成熟的安全框架解决方案一般有 A ...

  7. Spring Security调研记录【七】--核心模型与实现

    网上有非常多关于Spring Security文章中,都觉得Spring Security(相对于shiro)过于复杂,个人觉得复杂的是Spring Security的官方文档而不是Spring Se ...

  8. spring boot rest 接口集成 spring security(1) - 最简配置

    Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...

  9. SpringBoot + Spring Security 学习笔记(五)实现短信验证码+登录功能

    在 Spring Security 中基于表单的认证模式,默认就是密码帐号登录认证,那么对于短信验证码+登录的方式,Spring Security 没有现成的接口可以使用,所以需要自己的封装一个类似的 ...

随机推荐

  1. Thinkphp5获取文件上传信息

    Thinkphp5内置有处理文件上传的方法,因在开发文档没有找到获取上传文件基本信息的说明,故在这里做一下记录. $file = request()->file('input类型为file的na ...

  2. leetcood学习笔记-20

    python字符串与列表的相互转换   学习内容: 1.字符串转列表 2.列表转字符串 1. 字符串转列表 str1 = "hi hello world" print(str1.s ...

  3. apue 第18章 终端I/O

    终端I/O有两种不同的工作模式: (1)规范模式:输入以行单位进行处理,每个读请求也最多返回一行. (2)非规范模式:输入字符不装配成行. 终端设备是由通常位于内核中的终端驱动程序控制的.每个终端设备 ...

  4. (转)openfire插件开发(一)

    转:http://blog.csdn.net/lovexieyuan520/article/details/37774909 1. 在上一篇博文中,我介绍了Openfire3.9.3源代码导入ecli ...

  5. 卿烨科技 Fireball

    9人开发病毒感染超2亿电脑!Fireball病毒境外做案被举报   原标题:名校毕业生研发病毒年获利8000万 2.5亿台电脑感染 海淀网友协助民警追踪跨境黑客 高材生开公司研发病毒 一年获利8000 ...

  6. 用java打开一个本地文件

    以下有三种方式打开 /** * 借助java.awt.Desktop打开 * @see 打开的目录或文件名中允许包含空格 */ private static void useAWTDesktop() ...

  7. Maven 打包jar清单

    <project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plu ...

  8. build protobuf to a static library

    use ar cd src ar -cvq libprotobuf.a *.o

  9. node.js 从文件流中读写数据及管道流

    读取数据 // 引入 fs 模块 const fs = require('fs'); // 创建可读流 let readStream = fs.createReadStream('index.txt' ...

  10. MySQL将查询结果写入到文件的2种方法

    1.SELECT INTO OUTFIL: 这种方法不能覆盖或者追加到已经存在的文件,只能写入到新文件,并且建立文件的路径需要mysql进程用户有权限建立新文件. mysql 61571 60876 ...