Spring Security3配置使用说明

        Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

官方文档中文翻译:http://www.mossle.com/docs/springsecurity3/html/springsecurity.html

一、基本流程

Spring Security3对(用户登录)验证和(安全资源)授权的基本流程如下图:


1、Spring Security 核心

SecurityContextHolder 、SecurityContext 、Authentication 、GrantedAuthority 、UserDetails

Authentication:代表了Spring Security中的当事人。

SecurityContext:拥有了Authentication、请求相关的信息。

SecurityContextHodler:用于获取SecurityContext。

GrantedAuthority:代表在应用程序中给当事人授予的权限。

UserDetails:用户详细信息。其实就是一个JavaBean。

UserDetailsService:UserDetails相关的业务处理。

这几个是Spring Security的核心,其它的API都是围绕这些API展开的,都是为它们服务的。

2、身份认证Authentication

2.1、一般的身份认证

通常情况下,我们的系统都是这样的:

a. 用户输入用户名、密码登录

b. 系统对用户名、密码进行验证

c. 获取用户上下文信息(角色列表等等)

d. 获取相关操作权限

对于上面说的前三条,用Spring Security来处理,就是:

a. 用户名、密码组合生成一个Authentication对象(也就是UsernamePasswordAuthenticationToken对象)。

b. 生成的这个token对象会传递给一个AuthenticationManager对象用于验证。

c. 当成功认证后,AuthenticationManager返回一个Authentication对象。

d. 接下来,就可以调用

SecurityContextHodler.getContext().setAuthentication(…)。

2.2、Web Application中如何进行身份认证呢?

a. 用户在首页上点击某个链接

b. 后台处理时,先判断是否是要访问一个受保护的资源

c. 如果是受保护的资源,判断用户是否登录,是否有这个资源的访问权限

d. 如果用户没有登录,返回一个登录页面给用户

e. 用户输入username、password,然后登录

f. 接下来开始上面的身份认证过程

在Web Application环境下,将上述1-4过程由AuthenticationEntryPoint来处理。

用户要访问另外的资源时,肯定要判断是否有该资源的访问权限,在判断是否有访问权限前,一般要用户先登录系统(要对用户的身份进行认证)的。如果用户已经成功登录,只需要判断是否有访问权即可。在一般的Web Application中(不使用Spring Security),我们通常会将用户信息存储到HttpSession中。

3、授权Authorization(Access Control)

身份认证Authentication保证了用户可访问系统。权限认证(授权保证了用户可以访问系统中的资源)。

在用户的一次资源访问中,这两个过程是不可少的。Access Control就是决定你这个请求是否被允许,它是在身份认证之后,访问资源之前进行的。

用户请求-->身份认证-->授权-->资源访问-->响应

身份认证过程由AuthenticationManager来处理,授权决定则是由AccessDecisionManager来处理的。

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

Spring在进行授权时,充分利用了Spring的核心之一:AOP。AOP在程序中一般体现为Filter或者是Interceptor,其中更多的是使用Interceptor。

上面的decide方法需要三个参数:

·Authentication就是已经通过认证的Authentication对象。上面的学习已经可以理解。

·Object obj  是代表方法调用(MethodInvocation)或者请求处理(Action的Handler),在接下来的AbstractSecurityInterceptor中说明。

·configAttributes则是相关的特性配置。下面会有说明。

 

AbstractSecurityInterceptor

Security中关于授权部分使用了AOP,所以就不得不了解一下AbstractSecurityInterceptor。

Interceptor一般都会提供invoke方法。这个类是抽象类,没有提供,使用时用的是它的子类,在子类中提供了invoke方法。而在AccessDecisionManager的decide方法中的第二个参数,就是invoke方法的参数MethodInvocation对象。

ConfigAttribute

其实就是对某个拦截器配置一些访问属性。举个例子:

某个拦截器interceptor,配置访问属性有ROLE_A, ROLE_B,如果一个用户经过认证后他有一个Authentication为ROLE_A,那么他的这个请求就会被拦截器interceptor处理。

再说的通俗点就是:设置某个拦截器能够处理哪些身份的用户的请求。

AbstractSecurityInterceptor的执行流程

1、查找有哪些configAttributes与当前的请求相关联。

2、提交secure object(就是前面说的MethodInvocation对象)、当前的Authentication(就是已经认证好的身份)、以及1中找到的那些configAttributes,提交给AccessDecisionManager用于授权。

3、选择性的改变用户的身份去进行验证。这是因为用户身份的多样性的需要。

4、Secure Object(methodInvocation 对象执行),也就是执行我们在action中写的Handler。

5、如果配置了AfterInvocationManager,那么AfterInvocationManager也会执行的。

这个流程是官方文档中说明的,已经很清楚了。为了更清新的了解这个过程,还是查看一下源码吧:

在AbstractSecurityInterceptor的子类MethodSecurityInterceptor中:

public Object invoke(MethodInvocation mi) throws Throwable {// 预先处理  InterceptorStatusToken token = super.beforeInvocation(mi);  Object result;  try {// 真实方法调用,也就是我们写的action调用      result = mi.proceed();  } finally {      super.finallyInvocation(token);  }// afterInvocationManager处理  return super.afterInvocation(token, result);     }

这段代码与上面的流程说明对应起来,那就应该是上面说的流程中的1、2、3对应了这段代码中的 预先处理部分。就来看看beforeInvocation:

// 参数object就是方法调用protected InterceptorStatusToken beforeInvocation(Object object) {  Assert.notNull(object, "Object was null");  final boolean debug = logger.isDebugEnabled();   if (!getSecureObjectClass().isAssignableFrom(object.getClass())) {      throw new IllegalArgumentException("Security invocation attempted for object "        + object.getClass().getName()        + " but AbstractSecurityInterceptor only configured to support secure objects of type: "        + getSecureObjectClass());  }// 收集与方法调用相关的特性配置  Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object);   if (attributes == null || attributes.isEmpty()) {      if (rejectPublicInvocations) {    throw new IllegalArgumentException("Secure object invocation " + object +      " was denied as public invocations are not allowed via this interceptor. "        + "This indicates a configuration error because the "        + "rejectPublicInvocations property is set to 'true'");      }       if (debug) {    logger.debug("Public object - authentication not attempted");      }        publishEvent(new PublicInvocationEvent(object));      return null; // no further work post-invocation  }   if (debug) {      logger.debug("Secure object: " + object + "; Attributes: " + attributes);  }   if (SecurityContextHolder.getContext().getAuthentication() == null) {  credentialsNotFound(messages.getMessage("AbstractSecurityInterceptor.authenticationNotFound",        "An Authentication object was not found in the SecurityContext"), object, attributes);  }// 取得该用户已验证的身份  Authentication authenticated = authenticateIfRequired();   // Attempt authorization  try {     // 进行用户授权this.accessDecisionManager.decide(authenticated, object, attributes);  }  catch (AccessDeniedException accessDeniedException) {      publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated, accessDeniedException));      throw accessDeniedException;  }   if (debug) {      logger.debug("Authorization successful");  }   if (publishAuthorizationSuccess) {      publishEvent(new AuthorizedEvent(object, attributes, authenticated));  }// 切换为其他身份  // Attempt to run as a different user  Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attributes);    if (runAs == null) {      if (debug) {    logger.debug("RunAsManager did not change Authentication object");      }       // no further work post-invocation      return new InterceptorStatusToken(SecurityContextHolder.getContext(), false, attributes, object);  } else {      if (debug) {    logger.debug("Switching to RunAs Authentication: " + runAs);      }      SecurityContext origCtx = SecurityContextHolder.getContext();      SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());      SecurityContextHolder.getContext().setAuthentication(runAs);       // need to revert to token.Authenticated post-invocation      return new InterceptorStatusToken(origCtx, true, attributes, object);  }    }

二、Spring Security3的MAVEN坐标

<!-- Spring Security Start -->
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-web</artifactId>
  <version>3.1.2.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-taglibs</artifactId>
  <version>3.1.2.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-core</artifactId>
  <version>3.1.2.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-config</artifactId>
  <version>3.1.2.RELEASE</version>
</dependency>
<!-- Spring Security End -->


三、web.xml配置文件

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
 <filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>


四、spring security3 主要配置文件

 

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
http://www.springframework.org/schema/security 
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<global-method-security pre-post-annotations="enabled"></global-method-security>
<!-- 该路径下的资源不用过滤 -->
<http pattern="/include/js/**" security="none" />
<http pattern="/include/css/**" security="none" />
<http pattern="/include/scripts/**" security="none" />
<http pattern="/include/jsp/**" security="none" />
<http pattern="/images/**" security="none" />
<http pattern="/login.jsp" security="none" />
<!--auto-config = true 则使用from-login. 如果不使用该属性 则默认为http-basic(没有session). -->
<!-- lowercase-comparisons:表示URL比较前先转为小写。 -->
<!-- path-type:表示使用Apache Ant的匹配模式。 -->
<!--access-denied-page:访问拒绝时转向的页面。 -->
<!-- access-decision-manager-ref:指定了自定义的访问策略管理器。 -->
 
<http use-expressions="true" auto-config="true"
access-denied-page="/include/jsp/timeout.jsp">
<!--login-page:指定登录页面。 -->
<!-- login-processing-url:指定了客户在登录页面中按下 Sign In 按钮时要访问的 URL。 -->
<!-- authentication-failure-url:指定了身份验证失败时跳转到的页面。 -->
<!-- default-target-url:指定了成功进行身份验证和授权后默认呈现给用户的页面。 -->
<!-- always-use-default-target:指定了是否在身份验证通过后总是跳转到default-target-url属性指定的URL。 -->
 
<form-login login-page="/login.jsp" default-target-url='/system/default.jsp'
always-use-default-target="true" authentication-failure-url="/login.jsp?login_error=1" />
<!--logout-url:指定了用于响应退出系统请求的URL。其默认值为:/j_spring_security_logout。 -->
<!-- logout-success-url:退出系统后转向的URL。 -->
<!-- invalidate-session:指定在退出系统时是否要销毁Session。 -->
<logout invalidate-session="true" logout-success-url="/login.jsp"
logout-url="/j_spring_security_logout" />
<!-- 实现免登陆验证 -->
<remember-me />
 
<!-- max-sessions:允许用户帐号登录的次数。范例限制用户只能登录一次。 -->
<!-- 此值表示:用户第二次登录时,前一次的登录信息都被清空。 -->
<!-- exception-if-maximum-exceeded:默认为false, -->
<!-- 当exception-if-maximum-exceeded="true"时系统会拒绝第二次登录。 -->
<session-management invalid-session-url="/login.jsp"
session-fixation-protection="none">
<concurrency-control max-sessions="1"
error-if-maximum-exceeded="false" />
</session-management>
<custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR" />
<session-management session-authentication-strategy-ref="sas" />
 
</http>
<beans:bean id="sas"
class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
<beans:constructor-arg name="sessionRegistry"
ref="sessionRegistry" />
<beans:property name="maximumSessions" value="1" />
<!-- 防止session攻击 -->
<beans:property name="alwaysCreateSession" value="true" />
<beans:property name="migrateSessionAttributes" value="false" />
<!-- 同一个帐号 同时只能一个人登录 -->
<beans:property name="exceptionIfMaximumExceeded"
value="false" />
</beans:bean>
<beans:bean id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl" />
<!-- 事件监听:实现了ApplicationListener监听接口,包括AuthenticationCredentialsNotFoundEvent 
事件, -->
<!-- AuthorizationFailureEvent事件,AuthorizedEvent事件, PublicInvocationEvent事件 -->
<beans:bean class="org.springframework.security.authentication.event.LoggerListener" />
<!-- 自定义资源文件 提示信息 -->
<beans:bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<beans:property name="basenames" value="classpath:message_zh_CN">
</beans:property>
</beans:bean>
<!-- 配置过滤器 -->
<beans:bean id="myFilter"
class="com.taskmanager.web.security.MySecurityFilter">
<!-- 用户拥有的权限 -->
<beans:property name="authenticationManager" ref="myAuthenticationManager" />
<!-- 用户是否拥有所请求资源的权限 -->
<beans:property name="accessDecisionManager" ref="myAccessDecisionManager" />
<!-- 资源与权限对应关系 -->
<beans:property name="securityMetadataSource" ref="mySecurityMetadataSource" />
</beans:bean>
<!-- 实现了UserDetailsService的Bean -->
<authentication-manager alias="myAuthenticationManager">
<authentication-provider user-service-ref="myUserDetailServiceImpl">
<!-- 登入 密码 采用MD5加密 -->
<password-encoder hash="md5" ref="passwordEncoder">
</password-encoder>
</authentication-provider>
</authentication-manager>
<!-- 验证用户请求资源 是否拥有权限 -->
<beans:bean id="myAccessDecisionManager"
class="com.taskmanager.web.security.MyAccessDecisionManager">
</beans:bean>
<!-- 系统运行时加载 系统要拦截的资源 与用户请求时要过滤的资源 -->
<beans:bean id="mySecurityMetadataSource"
class="com.taskmanager.web.security.MySecurityMetadataSource">
<beans:constructor-arg name="powerService" ref="powerService">
</beans:constructor-arg>
</beans:bean>
<!-- 获取用户登入角色信息 -->
<beans:bean id="myUserDetailServiceImpl"
class="com.taskmanager.web.security.MyUserDetailServiceImpl">
<beans:property name="userService" ref="userService"></beans:property>
</beans:bean>
 
<!-- 用户的密码加密或解密 -->
<beans:bean id="passwordEncoder"
class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />
</beans:beans>

五、spring security3 主要实现类

1. MySecurityFilter.java 过滤用户请求

public class MySecurityFilter extends AbstractSecurityInterceptor implements
Filter {
// 与applicationContext-security.xml里的myFilter的属性securityMetadataSource对应,
// 其他的两个组件,已经在AbstractSecurityInterceptor定义
private FilterInvocationSecurityMetadataSource securityMetadataSource;
 
@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.securityMetadataSource;
}
 
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}
 
private void invoke(FilterInvocation fi) throws IOException,
ServletException {
// object为FilterInvocation对象
// super.beforeInvocation(fi);//源码
// 1.获取请求资源的权限
 //执行 Collection<ConfigAttribute> attributes = 
                        //securityMetadataSource.getAttributes(fi);
// 2.是否拥有权限
// this.accessDecisionManager.decide(authenticated, fi, attributes);
// this.accessDecisionManager.decide(authenticated, fi, attributes);
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} finally {
super.afterInvocation(token, null);
}
}
 
public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
return securityMetadataSource;
}
public void setSecurityMetadataSource(
FilterInvocationSecurityMetadataSource securityMetadataSource) {
this.securityMetadataSource = securityMetadataSource;
}
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
public void destroy() {
// TODO Auto-generated method stub
 
}
@Override
public Class<? extends Object> getSecureObjectClass() {
//下面的MyAccessDecisionManager的supports方面必须放回true,否则会提醒类型错误  
return FilterInvocation.class;
}
}

2. MyUserDetailServiceImpl.java 点击登入跳转 保存 用户权限 

public class MyUserDetailServiceImpl implements UserDetailsService {
 
UserInter userService;
public UserInter getUserService() {
return userService;
}
 
public void setUserService(UserInter userService) {
this.userService = userService;
}
 
// 登入默认会调整到这里
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
System.out.println("username is " + username);
TSysUser users=null;
try {
users = this.userService.findByUsersLogin(username);
} catch (LoginException e) {
throw new UsernameNotFoundException(username);
} catch (SystemRunException e) {
throw new UsernameNotFoundException(username);
}
if (users == null) {
throw new UsernameNotFoundException(username);
}else {
if(!users.getStatus()){
throw new UsernameNotFoundException("该用户处于锁定状态");
}
}
Collection<GrantedAuthority> grantedAuths = obtionGrantedAuthorities(users);
 
boolean enables = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
User userdetail = new User(users.getCode(), users.getPassword(),
enables, accountNonExpired, credentialsNonExpired,
accountNonLocked, grantedAuths);
return userdetail;
}
 
// 取得用户的权限
private Set<GrantedAuthority> obtionGrantedAuthorities(TSysUser user) {
Set<GrantedAuthority> authSet = new HashSet<GrantedAuthority>();
//获取用户所属组
Set<TSysUserofusergroup> userGroups = user.getTSysUserofusergroups();
for(TSysUserofusergroup userGroup : userGroups ){
//获取用户所属组 组对象
TSysUsergroup usgroup=userGroup.getTSysUsergroup();
//获取用户组对应 角色集合
Set<TSysCharofgroup> charofgroups=usgroup.getTSysCharofgroups();
for (TSysCharofgroup charofgroup : charofgroups) {
TSysCharacter character=charofgroup.getTSysCharacter();
//获取角色对应权限集合
Set<TSysPowersystemofchar>  powerSystemofchars=
                              character.getTSysPowersystemofchars();
for(TSysPowersystemofchar powerofchar : powerSystemofchars){
authSet.add(
   new GrantedAuthorityImpl(powerofchar.getTSysPowersystem().getRoleName()));
}
}
}
return authSet;
}
}

3. MySecurityMetadataSource.java 系统启动加载系统权限  用户登入验证权限

//1 加载资源与权限的对应关系  
 
/**
 * 该过滤器的主要作用就是通过spring著名的IoC生成securityMetadataSource。 
 * securityMetadataSource相当于本包中自定义的MyInvocationSecurityMetadataSourceService。 
 * 该MyInvocationSecurityMetadataSourceService的作用提从数据库提取权限和资源,装配到HashMap中, 
 * 供Spring Security使用,用于权限校验。 
 * @author sparta 11/3/29 
 */
public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {  
     //由spring调用  
     public MySecurityMetadataSource(PowerInter powerService) 
               throws SystemRunException {  
            this.powerService = powerService;  
            loadResourceDefine();  
        }  
      
        private PowerInter powerService;
        private static Map<String, Collection<ConfigAttribute>> resourceMap = null;  
     private RequestMatcher pathMatcher;
        public Collection<ConfigAttribute> getAllConfigAttributes() {  
         return new ArrayList<ConfigAttribute>();
        }  
      
        public boolean supports(Class<?> clazz) {  
            // TODO Auto-generated method stub  
            return true;  
        }  
        //加载所有资源与权限的关系  
        private void loadResourceDefine() throws SystemRunException {  
         if (resourceMap == null) {
     resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
     List<TSysPowersystem> resources = this.powerService
     .findByTSysPowersystem();
      for (TSysPowersystem resource : resources) {
     Collection<ConfigAttribute> configAttributes =
                                    new ArrayList<ConfigAttribute>();
     // 以权限名封装为Spring的security Object  
     //resource.getRoleName() 角色名称 可随意 role_admin  或者 admin
     ConfigAttribute configAttribute = 
                                    new SecurityConfig(resource.getRoleName());
     configAttributes.add(configAttribute);
     //resource.getInterceptUrl() 格式必须是 拦截的包路径  
                //或者是 比如  /manager/**/*.jh  或者  /system/manager/**/*.jsp
     resourceMap.put(resource.getInterceptUrl(), configAttributes);
      }
     }
                      
        }  
      //返回所请求资源所需要的权限  
        public Collection<ConfigAttribute> getAttributes(Object object)
                               throws IllegalArgumentException {  
         Iterator<String> it = resourceMap.keySet().iterator();
     while (it.hasNext()) {
     String resURL = it.next();
     Iterator<String> ite = resourceMap.keySet().iterator();
     pathMatcher = new AntPathRequestMatcher(resURL);
     if (pathMatcher.matches(((FilterInvocation) object).getRequest())) {
     Collection<ConfigAttribute> returnCollection =
                                          resourceMap.get(resURL);
     return returnCollection;
     }
     }
     return null;
        }  
    }  

4. MyAccessDecisionManager.java  验证是否拥有访问的权限

/** 
 *AccessdecisionManager在Spring security中是很重要的。 
 * 
 *在验证部分简略提过了,所有的Authentication实现需要保存在一个GrantedAuthority对象数组中。  
 *这就是赋予给主体的权限。 GrantedAuthority对象通过AuthenticationManager 
 *保存到 Authentication对象里,然后从AccessDecisionManager读出来,进行授权判断。  
 * 
 *Spring Security提供了一些拦截器,来控制对安全对象的访问权限,例如方法调用或web请求。  
 *一个是否允许执行调用的预调用决定,是由AccessDecisionManager实现的。  
 *这个 AccessDecisionManager 被AbstractSecurityInterceptor调用, 
 *它用来作最终访问控制的决定。 这个AccessDecisionManager接口包含三个方法:  
 * 
 void decide(Authentication authentication, Object secureObject, 
    List<ConfigAttributeDefinition> config) throws AccessDeniedException; 
 boolean supports(ConfigAttribute attribute); 
 boolean supports(Class clazz); 
  
  从第一个方法可以看出来,AccessDecisionManager使用方法参数传递所有信息,这好像在认证评估时进行决定。  
  特别是,在真实的安全方法期望调用的时候,传递安全Object启用那些参数。  
  比如,让我们假设安全对象是一个MethodInvocation。  
  很容易为任何Customer参数查询MethodInvocation, 
  然后在AccessDecisionManager里实现一些有序的安全逻辑,来确认主体是否允许在那个客户上操作。  
  如果访问被拒绝,实现将抛出一个AccessDeniedException异常。 
 
  这个 supports(ConfigAttribute) 方法在启动的时候被 
  AbstractSecurityInterceptor调用,来决定AccessDecisionManager 
  是否可以执行传递ConfigAttribute。  
  supports(Class)方法被安全拦截器实现调用, 
  包含安全拦截器将显示的AccessDecisionManager支持安全对象的类型。 
 */  
public class MyAccessDecisionManager implements AccessDecisionManager {  
          
        public void decide(Authentication authentication, Object object,
 ;           Collection<ConfigAttribute> configAttributes) 
           throws AccessDeniedException, InsufficientAuthenticationException {  
            if(configAttributes == null) {  
                return;  
            }  
            //所请求的资源拥有的权限(一个资源对多个权限)  
            Iterator<ConfigAttribute> iterator = configAttributes.iterator();  
            while(iterator.hasNext()) {  
                ConfigAttribute configAttribute = iterator.next();  
                //访问所请求资源所需要的权限  
                String needPermission = configAttribute.getAttribute();  
                System.out.println("needPermission is " + needPermission); 
                //用户所拥有的权限authentication  
                for(GrantedAuthority ga : authentication.getAuthorities()) {  
                    if(needPermission.equals(ga.getAuthority())) {  
                        return;  
                    }  
                }  
            }  
            //没有权限    会跳转到login.jsp页面
            throw new AccessDeniedException(" 没有权限访问");  
        }  
      
        public boolean supports(ConfigAttribute attribute) {  
            // TODO Auto-generated method stub  
            return true;  
        }  
      
        public boolean supports(Class<?> clazz) {  
            // TODO Auto-generated method stub  
            return true;  
        }  
          
    }  



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值