完整代码见附件

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. Mysql学习笔记(004)- 条件查询

    条件查询 #进阶2:条件查询 /* 语法: select 查询列表③ from 表名① where 条件筛选② 分类: 一.按条件表达式筛选 条件运算符:> < = != <> ...

  2. ( vant ) 新手踩坑

    最近在用vant 做H5 页面,坑太他娘的坑娘啊!!!!!!!!!!!!!!!! 1,修改vant组件样式问题 vant 修改组件的样式时,在scoped 属性下没有效果.如果去掉scope 会造成全 ...

  3. Ubuntu 16.04系统上修改Docker镜像的存储路径 (转)

    转自:https://blog.csdn.net/qihongchao/article/details/80651492 dba专门挂了一个硬盘让我放项目(测试环境)因为系统空间比较小,希望把dock ...

  4. Ubuntu下安装Samba服务器

    闲来无聊尝试自己安装下Samba服务器,使本机和虚拟机可以无障碍传输文件(虽然用VMwaretools可传,但总感觉麻烦,而且速度欠佳) 首先,同安装qemu一样,在安装之前要确定你的系统apt列表已 ...

  5. PHP面试 PHP基础知识 七(文件及目录处理)

    文件操作 文件打开函数 fopen()函数 //用来打开一个文件 打开时需要指定打开模式 语法:fopen( filename, mode, include_path, context); filen ...

  6. C++——异常

    1.throw表达式 if (item1.isbn()!=item2.isbn()) throw runtime_error("data must refer to the same ISB ...

  7. hql 跟 sql 区别

    hql 跟 sql 区别  1.hql与sql的区别 sql 面向数据库表查询 hql 面向对象查询 hql : from 后面跟的 类名+类对象 where 后 用对象的属性做条件 sql: fro ...

  8. 2-vim-打开和新建文件-01-打开/新建文件/打开定位到文件指定行

    1.新建或打开文件 命令: vim 文件名 在终端中输入vi在后面跟上文件名即可. 如果文件已经存在,会直接打开文件. 如果文件不存在,会新建一个文件. 2.打开文件并定位到文件指定行. 命令: vi ...

  9. linux下读取移动硬盘

    前提是安装了ntfs-3g软件,系统才能识别到移动硬盘. 第一步.fdisk -l    该命令查看系统识别到的磁盘,如果移动硬盘系统能够识别,    在屏幕上会输出“/dev/sdb1”之类的字样. ...

  10. Match & Catch CodeForces - 427D 后缀自动机水题

    题意: 给出两个字符串a,b,求一个字符串,这个字符串是a和b的子串, 且只在a,b中出现一次,要求输出这个字符串的最小长度. 题解: 将a串放入后缀自动机中,然后记录一下每个节点对应的子串出现的次数 ...