完整代码见附件

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. springboot设置静态资源缓存一年

    由于本人所在项目组,所用的项目是前后端分离的,前端是React 的SPA,每次打包都会新版本的静态文件. 然而,在有些时候,这些静态资源是不变的,故可以将资源缓存至用户本地,提升性能. 写法如下,需要 ...

  2. BZOJ 2655: calc(拉格朗日插值)

    传送门 解题思路 首先比较容易能想到\(dp\),设\(f[i][j]\)表示前\(j\)个数,每个数\(<=i\)的答案,那么有转移方程:\(f[i][j]=f[i-1][j-1]*i*j+f ...

  3. (转)OpenFire源码学习之二十七:Smack源码解析

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43484199 Smack Smack是一个用于和XMPP服务器通信的类库,由此可以实现即 ...

  4. codeforces 447E or 446C 线段树 + fib性质或二次剩余性质

    CF446C题意: 给你一个数列\(a_i\),有两种操作:区间求和:\(\sum_{i=l}^{r}(a[i]+=fib[i-l+1])\).\(fib\)是斐波那契数列. 思路 (一) codef ...

  5. nginx代理一个服务器上所有域名

    1. 主配置文件不需要更改任何配置2. 在vhosts目录下需要建立两个文件,一个是servername 列表文件,一个是虚拟主机配置文件两个文件内容分别为 #() servername server ...

  6. System之nanoTime函数

    原文地址:https://blog.csdn.net/yumolan4325/article/details/79201766 1 System有一个静态的函数nanoTime函数,该函数是返回纳秒的 ...

  7. 作用域 {}代码块 const修饰符 引用

    简单分为:全局作用域.局部作用域.语句作用域 如果希望在局部变量的作用域内使用同名的全局变量,可以在该变量前加上“::” ::aver=20 #include<iostream> usin ...

  8. PAT_A1048#Find Coins

    Source: PAT A1048 Find Coins (25 分) Description: Eva loves to collect coins from all over the univer ...

  9. MySQL数据库(六) —— SQL注入攻击、视图、事物、存储过程、流程控制

    SQL注入攻击.视图.事物.存储过程.流程控制 一.SQL注入攻击 1.什么是SQL注入攻击 import pymysql conn = pymysql.Connect( user="roo ...

  10. 线性回归——Python代码实现

    import numpy as np def computer_error_for_give_point(w, b, points): # 计算出 观测值与计算值 之间的误差, 并累加,最后返回 平均 ...