定义决策管理器及修改权限前缀(转)

首先介绍下Spring的决策管理器,其接口为AccessDecisionManager,抽象类为AbstractAccessDecisionManager。而我们要自定义决策管理器的话一般是继承抽象类而不去直接实现接口。
在Spring中引入了投票器(AccessDecisionVoter)的概念,有无权限访问的最终觉得权是由投票器来决定的,最常见的投票器为RoleVoter,在RoleVoter中定义了权限的前缀,先看下Spring在RoleVoter中是怎么处理授权的。

public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
    int result = ACCESS_ABSTAIN;
    Collection<? extends GrantedAuthority> authorities = extractAuthorities(authentication);

    for (ConfigAttribute attribute : attributes) {
        if (this.supports(attribute)) {
            result = ACCESS_DENIED;

            // Attempt to find a matching granted authority
            for (GrantedAuthority authority : authorities) {
                if (attribute.getAttribute().equals(authority.getAuthority())) {
                    return ACCESS_GRANTED;
                }
            }
        }
    }

    return result;
}

Collection<? extends GrantedAuthority> extractAuthorities(Authentication authentication) {
    return authentication.getAuthorities();
}

Authentication中是用户及用户权限信息,attributes是访问资源需要的权限,然后循环判断用户是否有访问资源需要的权限,如果有就返回ACCESS_GRANTED,通俗的说就是有权限。

Spring提供了3个决策管理器,至于这三个管理器是如何工作的请查看SpringSecurity源码

AffirmativeBased 一票通过,只要有一个投票器通过就允许访问

ConsensusBased 有一半以上投票器通过才允许访问资源

UnanimousBased 所有投票器都通过才允许访问

下面来实现一个简单的自定义决策管理器,这个决策管理器并没有使用投票器

public class DefaultAccessDecisionManager extends AbstractAccessDecisionManager {

	public void decide( Authentication authentication, Object object,
			Collection<ConfigAttribute> configAttributes)
		throws AccessDeniedException, InsufficientAuthenticationException{

		SysUser user = (SysUser)authentication.getPrincipal();
		logger.info("访问资源的用户为"+user.getUsername());

		//如果访问资源不需要任何权限则直接通过
		if( configAttributes == null ) {
			return ;
		}

		Iterator<ConfigAttribute> ite = configAttributes.iterator();
		//遍历configAttributes看用户是否有访问资源的权限
		while( ite.hasNext()){

			ConfigAttribute ca = ite.next();
			String needRole = ((SecurityConfig)大专栏  定义决策管理器及修改权限前缀(转)">ca).getAttribute();

			//ga 为用户所被赋予的权限。 needRole 为访问相应的资源应该具有的权限。
			for( GrantedAuthority ga: authentication.getAuthorities()){

				if(needRole.trim().equals(ga.getAuthority().trim())){

					return;
				}

			}

		}

		throw new AccessDeniedException("");

	}
}

decide这个方法没有任何的返回值,需要在没有通过授权时抛出AccessDeniedException。

如果有访问某个资源需要同时拥有两个或两个以上权限的情况,这时候就要通过自定义AccessDecisionVoter来实现了,这个也很简单在这里就不赘述了。如果要在页面中使用hasRole()这样的表达式就需要注入WebExpressionVoter了。

在SpringSecurity中自定义权限前

权限的前缀默认是ROLE_,网上的很多例子是说,直接在配置文件中加上下面的配置就可以了。

<bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter">
  <property name="rolePrefix" value="AUTH_"></property>
</bean>

亲测不管用的,我想应该不是我配置的问题,而是在我们配置了http auto-config=”true”Spring就已经将AccessDecisionManager初始化好了,即便配置到之前也不行,因为这个初始化是Spring自己来完成的,它并没有把你配置的roleVoter注入到AccessDecisionManager中。那我们就来手动的注入AccessDecisionManager吧。
在http配置中有个access-decision-manager-ref属性,可以使我们手动注入AccessDecisionManager,下面是详细配置

<sec:http auto-config="true" access-decision-manager-ref="accessDecisionManager">

  <sec:access-denied-handler ref="accessDeniedHandler"/>

  <sec:session-management invalid-session-url="/login.jsp" />

  <sec:intercept-url pattern="/app.jsp" access="AUTH_GG_FBGBGG"/>
  <sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />

  <sec:form-login login-page="/login.jsp" authentication-failure-url="/login.jsp"
    default-target-url="/index.jsp"/>

</sec:http>

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
  <constructor-arg name="decisionVoters">
    <list>
      <ref bean="roleVoter"/>
      <ref bean="authenticatedVoter"/>
    </list>
  </constructor-arg>
  <property name="messageSource" ref="messageSource"></property>
</bean>

<bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter">
  <property name="rolePrefix" value=""></property>
</bean>

<bean id="authenticatedVoter" class="org.springframework.security.access.vote.AuthenticatedVoter" />

在这里我们就不用自定义的AccessDecisionManager了,直接用Spring的AffirmativeBased,因为Spring本身提供的这些决策管理器就已经很强大了。
配置很简单,要想修改权限的前缀只需要修改roleVoter中的rolePrefix就可以了,如果不要前缀就让它为“”。
authenticatedVoter是为了支持IS_AUTHENTICATED这种认证,authenticatedVoter提供的3种认证,分别是
IS_AUTHENTICATED_ANONYMOUSLY 允许匿名用户进入
IS_AUTHENTICATED_FULLY 允许登录用户进入
IS_AUTHENTICATED_REMEMBERED 允许登录用户和rememberMe用户进入

原文链接

原文地址:https://www.cnblogs.com/dajunjun/p/11712913.html

时间: 2024-12-26 02:51:55

定义决策管理器及修改权限前缀(转)的相关文章

Spring Security入门(3-5)Spring Security 的鉴权 - 决策管理器和投票器

1.决策管理器的运行原理: 2.Spring Security提供的决策管理器实现 3.用户自定义的决策管理器

Altium原理图中利用封装管理器批量修改元器件封装

批量修改封装,或者别人拿来原理图让我们画板时,发现封装全不对.如果原理图中同样封装的器件很多时,那么批量修改封装将大大减少你的工作量.下面将我批量修改封装的方法共享给大家. 在原理图界面,打开封装管理器:快捷键T-G,如图,在Design Item ID下选择需要修改的元器件ID,这个ID在设计原理图就确定了,不可以随便改变.如果全局修改本类别的元器件选择这个选项.也可以根据需求选择其他选项.如图,选中需要更改的PC814,并全选. 在图的右下角有Add添加按钮,添加封装,如图: 这时在窗口可以

Eclipse包管理器字体修改

打开eclipse 下的plugins 文件夹 找到 org.eclipse.ui.themes_xxxxx文件夹 打开css文件夹 打开 e4_default_win7文件 在末尾处追加 #org-eclipse-jdt-ui-PackageExplorer Tree,#org-eclipse-ui-navigator-ProjectExplorer Tree {  font-size: 10px; /* 你需要的字体大小*/} 当然你可以追加其他CSS属性 例如 font-family 修改

MQ队列管理器搭建(一)

多应用单MQ使用场景 如上图所示,MQ独立安装,或者与其中一个应用同处一机.Application1与Application2要进行通信,但因为跨系统,所以引入中间件来实现需求. Application1需要连接MQ,并将消息放入队列Queue中,Application2同样连接MQ,监听在Queue队列上,一旦发现有消息进入则取出该消息进行处理. 下面将给出创建队列管理器和队列的示例: 定义队列管理器名称为Qm1,本地队列名称为Queue,服务器连接通道CHAN_SERVER_CON,监听端口

记一次AD域域管理员密码更改导致某系统群集管理器故障排查解决过程

环境描述 某公司有一套系统,2台Windows2003系统,采用自带的群集管理器功能实现双机热备功能,正常情况下,服务器10.1.1.1承载中间件应用服务,服务器10.1.1.2承载数据库服务,仅当其中一台服务器故障时才会把资源切换至另一台. 系统名称 系统版本 IP地址 备注 S-EIP-APP Windows2003ENTSP2 10.1.1.1 采用Windows2003自带的群集管理器实现双机热备功能 S-EIP-DATA Windows2003ENTSP2 10.1.1.2 故障表现

Android-Activity程序动态的生成表格布局管理器

.java代码如下: package org.lxh.demo; import android.app.Activity; import android.os.Bundle; import android.view.ViewGroup; import android.widget.TableLayout; import android.widget.TableRow; import android.widget.TextView; public class MyTableLayoutDemo e

[django]上下文管理器

上下文管理器django提取context中的数据去供模板调用 需求: 所有的页面都需要一个特定的变量 本质: python函数 , 接收一个HttpRequest对象的参数 , 且返回的必须是一个字典 定义上下文管理器文件名命名不受限, 放置的路径也不受拘束, 可以放在django项目下的任意位置 定义 def my_name(request): return {'name': 'Jack'}12写好之后去settings.py中去注册 TEMPLATES = [ ... 'context_p

Struts2自己定义拦截器实例—登陆权限验证

版本号:struts2.1.6 此实例实现功能:用户须要指定username登陆,登陆成功进入对应页面运行操作,否则返回到登陆页面进行登陆,当直接訪问操作页面(登陆后才干訪问的页面)时则不同意,须返回登陆页面. 代码例如以下: 一.页面 login.jsp <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUB

如何修改CAD绘图线宽,多线样式管理器

如何修改CAD绘图线宽,多线样式管理器.今天小编就和大家简单探讨一下具体的操作步骤.具体演示步骤如下: 步骤一:多线样式管理器(M) 首先,我们先运行迅捷CAD编辑器专业版软件,点击"格式-多线样式管理器(M)",这时候会弹出弹窗. 步骤二:在多线样式管理器里操作以下2个步骤: 在"多线样式管理器"里,我们点击"standard"右侧的"新建"创建新的多线样式: 在"创建新多线样式"弹窗里,我们点击样式名命