Java后台框架篇--Springsecurity(一)

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

如何使用spring security,相信百度过的都知道,总共有四种用法,从简到深为:1、不用数据库,全部数据写在配置文件,这个也是官方文档里面的demo;2、使用数据库,根据spring security默认实现代码设计数据库,也就是说数据库已经固定了,这种方法不灵活,而且那个数据库设计得很简陋,实用性差;3、spring security和Acegi不同,它不能修改默认filter了,但支持插入filter,所以根据这个,我们可以插入自己的filter来灵活使用;4、暴力手段,修改源码,前面说的修改默认filter只是修改配置文件以替换filter而已,这种是直接改了里面的源码,但是这种不符合OO设计原则,而且不实际,不可用。

本文面向读者:

因为本文准备介绍第三种方法,所以面向的读者是已经具备了spring security基础知识的。不过不要紧,读者可以先看一下这个教程,看完应该可以使用第二种方法开发了。

spring security的简单原理:

使用众多的拦截器对url拦截,以此来管理权限。但是这么多拦截器,笔者不可能对其一一来讲,主要讲里面核心流程的两个。

首先,权限管理离不开登陆验证的,所以登陆验证拦截器AuthenticationProcessingFilter要讲;还有就是对访问的资源管理吧,所以资源管理拦截器AbstractSecurityInterceptor要讲;但拦截器里面的实现需要一些组件来实现,所以就有了AuthenticationManager、accessDecisionManager等组件来支撑。

现在先大概过一遍整个流程,用户登陆,会被AuthenticationProcessingFilter拦截,调用AuthenticationManager的实现,而且AuthenticationManager会调用ProviderManager来获取用户验证信息(不同的Provider调用的服务不同,因为这些信息可以是在数据库上,可以是在LDAP服务器上,可以是xml配置文件上等),如果验证通过后会将用户的权限信息封装一个User放到spring的全局缓存SecurityContextHolder中,以备后面访问资源时使用。

访问资源(即授权管理),访问url时,会通过AbstractSecurityInterceptor拦截器拦截,其中会调用FilterInvocationSecurityMetadataSource的方法来获取被拦截url所需的全部权限,在调用授权管理器AccessDecisionManager,这个授权管理器会通过spring的全局缓存SecurityContextHolder获取用户的权限信息,还会获取被拦截的url和被拦截url所需的全部权限,然后根据所配的策略(有:一票决定,一票否定,少数服从多数等),如果权限足够,则返回,权限不够则报错并调用权限不足页面。

虽然讲得好像好复杂,读者们可能有点晕,不过不打紧,真正通过代码的讲解在后面,读者可以看完后面的代码实现,再返回看这个简单的原理,可能会有不错的收获。

spring security使用实现(基于spring security3.1.4):

javaEE的入口:web.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<? xml version = "1.0" encoding = "UTF-8" ?> 
< web-app version = "2.5" xmlns = "http://java.sun.com/xml/ns/javaee" 
     xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" >  
      <!--加载Spring XML配置文件 --> 
     < context-param > 
         < param-name >contextConfigLocation</ param-name > 
         < param-value > classpath:securityConfig.xml           </ param-value > 
     </ context-param >  
       <!-- Spring Secutiry3.1的过滤器链配置 --> 
     < 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 容器启动监听器 --> 
     < listener > 
         < listener-class >org.springframework.web.context.ContextLoaderListener</ listener-class > 
     </ listener >    
       <!--系统欢迎页面 --> 
     < welcome-file-list > 
         < welcome-file >index.jsp</ welcome-file > 
     </ welcome-file-list > 
</ web-app >

上面那个配置不用多说了吧

直接上spring security的配置文件securityConfig.xml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?xml version= "1.0" encoding= "UTF-8" ?> 
<b:beans xmlns= "http://www.springframework.org/schema/security" 
     xmlns:b= "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"> 
 
   <!--登录页面不过滤 --> 
     <http pattern= "/login.jsp" security= "none" /> 
     <http access-denied-page= "/accessDenied.jsp" > 
         <form-login login-page= "/login.jsp" /> 
         <!--访问/admin.jsp资源的用户必须具有ROLE_ADMIN的权限 --> 
         <!-- <intercept-url pattern= "/admin.jsp" access= "ROLE_ADMIN" /> --> 
         <!--访问/**资源的用户必须具有ROLE_USER的权限 --> 
         <!-- <intercept-url pattern= "/**" access= "ROLE_USER" /> --> 
         <session-management> 
             <concurrency-control max-sessions= "1" 
                 error- if -maximum-exceeded= "false" /> 
         </session-management> 
         <!--增加一个filter,这点与 Acegi是不一样的,不能修改默认的filter了, 这个filter位于FILTER_SECURITY_INTERCEPTOR之前 --> 
         <custom-filter ref= "myFilter" before= "FILTER_SECURITY_INTERCEPTOR" /> 
     </http> 
     <!--一个自定义的filter,必须包含 authenticationManager,accessDecisionManager,securityMetadataSource三个属性,  
         我们的所有控制将在这三个类中实现,解释详见具体配置 --> 
     <b:bean id= "myFilter" 
         class = "com.erdangjiade.spring.security.MyFilterSecurityInterceptor" > 
         <b:property name= "authenticationManager" ref= "authenticationManager" /> 
         <b:property name= "accessDecisionManager" ref= "myAccessDecisionManagerBean" /> 
         <b:property name= "securityMetadataSource" ref= "securityMetadataSource" /> 
     </b:bean> 
     <!--验证配置,认证管理器,实现用户认证的入口,主要实现UserDetailsService接口即可 --> 
     <authentication-manager alias= "authenticationManager" > 
         <authentication-provider user-service-ref= "myUserDetailService" > 
             <!--如果用户的密码采用加密的话 <password-encoder hash= "md5" /> --> 
         </authentication-provider> 
     </authentication-manager> 
     <!--在这个类中,你就可以从数据库中读入用户的密码,角色信息,是否锁定,账号是否过期等 --> 
     <b:bean id= "myUserDetailService" class = "com.erdangjiade.spring.security.MyUserDetailService" /> 
     <!--访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 --> 
     <b:bean id= "myAccessDecisionManagerBean" 
         class = "com.erdangjiade.spring.security.MyAccessDecisionManager" > 
     </b:bean> 
     <!--资源源数据定义,将所有的资源和权限对应关系建立起来,即定义某一资源可以被哪些角色访问 --> 
     <b:bean id= "securityMetadataSource" 
         class = "com.erdangjiade.spring.security.MyInvocationSecurityMetadataSource" />  
 
  </b:beans>

其实所有配置都在<http></http>里面,首先这个版本的spring security不支持了filter=none的配置了,改成了独立的<http pattern=”/login.jsp” security=”none”/>,里面你可以配登陆页面、权限不足的返回页面、注销页面等,上面那些配置,我注销了一些资源和权限的对应关系,笔者这里不需要在这配死它,可以自己写拦截器来获得资源与权限的对应关系。

session-management是用来防止多个用户同时登陆一个账号的。

最重要的是笔者自己写的拦截器myFilter(终于讲到重点了),首先这个拦截器会加载在FILTER_SECURITY_INTERCEPTOR之前(配置文件上有说),最主要的是这个拦截器里面配了三个处理类,第一个是authenticationManager,这个是处理验证的,这里需要特别说明的是:这个类不单只这个拦截器用到,还有验证拦截器AuthenticationProcessingFilter也用到 了,而且实际上的登陆验证也是AuthenticationProcessingFilter拦截器调用authenticationManager来处理的,我们这个拦截器只是为了拿到验证用户信息而已(这里不太清楚,因为authenticationManager笔者设了断点,用户登陆后再也没调用这个类了,而且调用这个类时不是笔者自己写的那个拦截器调用的,看了spring技术内幕这本书才知道是AuthenticationProcessingFilter拦截器调用的)。

securityMetadataSource这个用来加载资源与权限的全部对应关系的,并提供一个通过资源获取所有权限的方法。

accessDecisionManager这个也称为授权器,通过登录用户的权限信息、资源、获取资源所需的权限来根据不同的授权策略来判断用户是否有权限访问资源。

authenticationManager类可以有许多provider(提供者)提供用户验证信息,这里笔者自己写了一个类myUserDetailService来获取用户信息。

MyUserDetailService:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.erdangjiade.spring.security; 
 
import java.util.ArrayList; 
import java.util.Collection; 
 
import org.springframework.dao.DataAccessException; 
import org.springframework.security.core.GrantedAuthority; 
import org.springframework.security.core.authority.GrantedAuthorityImpl; 
import org.springframework.security.core.userdetails.User; 
import org.springframework.security.core.userdetails.UserDetails; 
import org.springframework.security.core.userdetails.UserDetailsService; 
import org.springframework.security.core.userdetails.UsernameNotFoundException; 
 
public class MyUserDetailService implements UserDetailsService {  
 
     //登陆验证时,通过username获取用户的所有权限信息, 
     //并返回User放到spring的全局缓存SecurityContextHolder中,以供授权器使用 
     public UserDetails loadUserByUsername(String username)  
             throws UsernameNotFoundException, DataAccessException {    
         Collection<GrantedAuthority> auths= new ArrayList<GrantedAuthority>();  
 
         GrantedAuthorityImpl auth2= new GrantedAuthorityImpl( "ROLE_ADMIN" );  
         GrantedAuthorityImpl auth1= new GrantedAuthorityImpl( "ROLE_USER" );  
 
         if (username.equals( "lcy" )){  
             auths= new ArrayList<GrantedAuthority>();  
             auths.add(auth1); 
             auths.add(auth2);       
         }      
 
         User user = new User(username, "lcy" , true , true , true , true , auths);  
         return user;   
         }  
     }

其中UserDetailsService接口是spring提供的,必须实现的。别看这个类只有一个方法,而且这么简单,其中内涵玄机。

读者看到这里可能就大感疑惑了,不是说好的用数据库吗?对,但别急,等笔者慢慢给你们解析。

首先,笔者为什么不用数据库,还不是为了读者们测试方便,并简化spring security的流程,让读者抓住主线,而不是还要烦其他事(导入数据库,配置数据库,写dao等)。

这里笔者只是用几个数据模拟了从数据库中拿到的数据,也就是说ROLE_ADMIN、ROLE_USER、lcy(第一个是登陆账号)、lcy(第二个是密码)是从数据库拿出来的,这个不难实现吧,如果需要数据库时,读者可以用自己写的dao通过参数username来查询出这个用户的权限信息(或是角色信息,就是那个ROLE_*,对必须是ROLE_开头的,不然spring security不认账的,其实是spring security里面做了一个判断,必须要ROLE_开头,读者可以百度改一下),再返回spring自带的数据模型User即可。

这个写应该比较清晰、灵活吧,总之数据读者们通过什么方法获取都行,只要返回一个User对象就行了。(这也是笔者为什么要重写这个类的原因)

    通过MyUserDetailService拿到用户信息后,authenticationManager对比用户的密码(即验证用户),然后这个AuthenticationProcessingFilter拦截器就过咯。

下面要说的是另外一个拦截器,就是笔者自己写的拦截器MyFilterSecurityInterceptor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.erdangjiade.spring.security; 
 
import java.io.IOException; 
 
import javax.servlet.Filter; 
import javax.servlet.FilterChain; 
import javax.servlet.FilterConfig; 
import javax.servlet.ServletException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 
 
import org.springframework.security.access.SecurityMetadataSource; 
import org.springframework.security.access.intercept.AbstractSecurityInterceptor; 
import org.springframework.security.access.intercept.InterceptorStatusToken; 
import org.springframework.security.web.FilterInvocation; 
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; 
 
public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor  implements Filter {   
 
     //配置文件注入 
     private FilterInvocationSecurityMetadataSource securityMetadataSource; 
 
     //登陆后,每次访问资源都通过这个拦截器拦截 
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {  
         FilterInvocation fi = new FilterInvocation(request, response, chain);  
         invoke(fi);   
         } 
 
     public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {   
         return this .securityMetadataSource;   
         }    
 
     public Class<? extends Object> getSecureObjectClass() {  
         return FilterInvocation. class ;     
         }   
 
     public void invoke(FilterInvocation fi) throws IOException, ServletException { 
         //fi里面有一个被拦截的url 
         //里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限 
         //再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够 
         InterceptorStatusToken token = super .beforeInvocation(fi); 
         try { 
             //执行下一个拦截器 
             fi.getChain().doFilter(fi.getRequest(), fi.getResponse());    
             } finally {  
                 super .afterInvocation(token, null );   
             }    
         }   
     public SecurityMetadataSource obtainSecurityMetadataSource() {  
         return this .securityMetadataSource;    
         }  
     public void setSecurityMetadataSource( 
             FilterInvocationSecurityMetadataSource newSource) 
     {  
         this .securityMetadataSource = newSource;  
     }  
     public void destroy() {   
 
     }    
     public void init(FilterConfig arg0) throws ServletException {   
 
     }   
}

继承AbstractSecurityInterceptor、实现Filter是必须的。

首先,登陆后,每次访问资源都会被这个拦截器拦截,会执行doFilter这个方法,这个方法调用了invoke方法,其中fi断点显示是一个url(可能重写了toString方法吧,但是里面还有一些方法的),最重要的是beforeInvocation这个方法,它首先会调用MyInvocationSecurityMetadataSource类的getAttributes方法获取被拦截url所需的权限,在调用MyAccessDecisionManager类decide方法判断用户是否够权限。弄完这一切就会执行下一个拦截器。

再看一下这个MyInvocationSecurityMetadataSource的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.erdangjiade.spring.security; 
 
import java.util.ArrayList; 
import java.util.Collection; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.Map; 
 
import org.springframework.security.access.ConfigAttribute; 
import org.springframework.security.access.SecurityConfig; 
import org.springframework.security.web.FilterInvocation; 
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; 
 
import com.erdangjiade.spring.security.tool.AntUrlPathMatcher; 
import com.erdangjiade.spring.security.tool.UrlMatcher; 
 
public class MyInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {  
     private UrlMatcher urlMatcher = new AntUrlPathMatcher();  
     private static Map<String, Collection<ConfigAttribute>> resourceMap = null ; 
 
     //tomcat启动时实例化一次 
     public MyInvocationSecurityMetadataSource() { 
         loadResourceDefine();   
         }    
     //tomcat开启时加载一次,加载所有url和权限(或角色)的对应关系 
     private void loadResourceDefine() { 
         resourceMap = new HashMap<String, Collection<ConfigAttribute>>();  
         Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();  
         ConfigAttribute ca = new SecurityConfig( "ROLE_USER" ); 
         atts.add(ca);  
         resourceMap.put( "/index.jsp" , atts);   
         Collection<ConfigAttribute> attsno = new ArrayList<ConfigAttribute>(); 
         ConfigAttribute cano = new SecurityConfig( "ROLE_NO" ); 
         attsno.add(cano); 
         resourceMap.put( "/other.jsp" , attsno);    
         }   
 
     //参数是要访问的url,返回这个url对于的所有权限(或角色) 
     public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {  
         // 将参数转为url     
         String url = ((FilterInvocation)object).getRequestUrl();    
         Iterator<String>ite = resourceMap.keySet().iterator();  
         while (ite.hasNext()) {          
             String resURL = ite.next();   
             if (urlMatcher.pathMatchesUrl(resURL, url)) {  
                 return resourceMap.get(resURL);          
                 }        
             }  
         return null ;     
         }   
     public boolean supports(Class<?>clazz) {  
             return true ;   
             }  
     public Collection<ConfigAttribute> getAllConfigAttributes() {  
         return null ;   
         } 
     }

实现FilterInvocationSecurityMetadataSource接口也是必须的。

首先,这里也是模拟了从数据库中获取信息。

其中loadResourceDefine方法不是必须的,这个只是加载所有的资源与权限的对应关系并缓存起来,避免每次获取权限都访问数据库(提高性能),然后getAttributes根据参数(被拦截url)返回权限集合。

这种缓存的实现其实有一个缺点,因为loadResourceDefine方法是放在构造器上调用的,而这个类的实例化只在web服务器启动时调用一次,那就是说loadResourceDefine方法只会调用一次,如果资源和权限的对应关系在启动后发生了改变,那么缓存起来的就是脏数据,而笔者这里使用的就是缓存数据,那就会授权错误了。但如果资源和权限对应关系是不会改变的,这种方法性能会好很多。

现在说回有数据库的灵活实现,读者看到这,可能会说,这还不简单,和上面MyUserDetailService类一样使用dao灵活获取数据就行啦。

如果读者这样想,那只想到了一半,想一下spring的机制(依赖注入),dao需要依赖注入吧,但这是在启动时候,那个dao可能都还没加载,所以这里需要读者自己写sessionFactory,自己写hql或sql,对,就在loadResourceDefine方法里面写(这个应该会写吧,基础来的)。那如果说想用第二种方法呢(就是允许资源和权限的对应关系改变的那个),那更加简单,根本不需要loadResourceDefine方法了,直接在getAttributes方法里面调用dao(这个是加载完,后来才会调用的,所以可以使用dao),通过被拦截url获取数据库中的所有权限,封装成Collection<ConfigAttribute>返回就行了。(灵活、简单)

注意:接口UrlMatcher和实现类AntUrlPathMatcher是笔者自己写的,这本来是spring以前版本有的,现在没有了,但是觉得好用就用会来了,直接上代码(读者也可以自己写正则表达式验证被拦截url和缓存或数据库的url是否匹配):

1
2
3
4
5
6
7
8
package com.erdangjiade.spring.security.tool; 
 
public interface UrlMatcher{ 
     Object compile(String paramString); 
     boolean pathMatchesUrl(Object paramObject, String paramString); 
     String getUniversalMatchPattern();  
     boolean requiresLowerCaseUrl(); 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.erdangjiade.spring.security.tool;  
import org.springframework.util.AntPathMatcher; 
import org.springframework.util.PathMatcher;  
 
   public class AntUrlPathMatcher implements UrlMatcher {   
       private boolean requiresLowerCaseUrl; 
       private PathMatcher pathMatcher;  
       public AntUrlPathMatcher()   {  
           this ( true );  
 
   }   
       public AntUrlPathMatcher( boolean requiresLowerCaseUrl)  
       {   
           this .requiresLowerCaseUrl = true ; 
       this .pathMatcher = new AntPathMatcher();  
       this .requiresLowerCaseUrl = requiresLowerCaseUrl; 
       }  
 
       public Object compile(String path) {  
           if ( this .requiresLowerCaseUrl) {  
               return path.toLowerCase();   
               }    
           return path;   
       }   
 
       public void setRequiresLowerCaseUrl( boolean requiresLowerCaseUrl){ 
 
           this .requiresLowerCaseUrl = requiresLowerCaseUrl;  
       }  
 
       public boolean pathMatchesUrl(Object path, String url) {  
           if (( "/**" .equals(path)) || ( "**" .equals(path))) { 
               return true ;      
               }   
 
           return this .pathMatcher.match((String)path, url);  
       }  
 
       public String getUniversalMatchPattern() { 
           return "/**" ;   
       } 
 
       public boolean requiresLowerCaseUrl() {  
           return this .requiresLowerCaseUrl;   
       }   
 
       public String toString() {   
           return super .getClass().getName() + "[requiresLowerCase='"  
       + this .requiresLowerCaseUrl + "']" ;   
       } 
   }

然后MyAccessDecisionManager类的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.erdangjiade.spring.security; 
 
import java.util.Collection; 
import java.util.Iterator; 
 
import org.springframework.security.access.AccessDecisionManager; 
import org.springframework.security.access.AccessDeniedException; 
import org.springframework.security.access.ConfigAttribute; 
import org.springframework.security.access.SecurityConfig; 
import org.springframework.security.authentication.InsufficientAuthenticationException; 
import org.springframework.security.core.Authentication; 
import org.springframework.security.core.GrantedAuthority; 
 
public class MyAccessDecisionManager implements AccessDecisionManager { 
 
     //检查用户是否够权限访问资源 
     //参数authentication是从spring的全局缓存SecurityContextHolder中拿到的,里面是用户的权限信息 
     //参数object是url 
     //参数configAttributes所需的权限 
     public void decide(Authentication authentication, Object object,     
             Collection<ConfigAttribute> configAttributes)  
                     throws AccessDeniedException, InsufficientAuthenticationException { 
         if (configAttributes == null ){  
             return ;        
         }   
 
         Iterator<ConfigAttribute> ite=configAttributes.iterator(); 
         while (ite.hasNext()){ 
             ConfigAttribute ca=ite.next();   
             String needRole=((SecurityConfig)ca).getAttribute(); 
             for (GrantedAuthority ga : authentication.getAuthorities()){  
                 if (needRole.equals(ga.getAuthority())){   
 
                     return ;               
         }             
     }       
}  
         //注意:执行这里,后台是会抛异常的,但是界面会跳转到所配的access-denied-page页面 
         throw new AccessDeniedException( "no right" );    
}    
     public boolean supports(ConfigAttribute attribute) {  
         return true ; 
     }   
     public boolean supports(Class<?>clazz) { 
         return true ;  
         }  
     }

接口AccessDecisionManager也是必须实现的。

decide方法里面写的就是授权策略了,笔者的实现是,没有明说需要权限的(即没有对应的权限的资源),可以访问,用户具有其中一个或多个以上的权限的可以访问。这个就看需求了,需要什么策略,读者可以自己写其中的策略逻辑。通过就返回,不通过抛异常就行了,spring security会自动跳到权限不足页面(配置文件上配的)。

就这样,整个流程过了一遍。

权限框架SpringSecurity介绍 目前市面上比较流行的权限框架主要实Shiro和Spring Security,这两个框架各自侧重点不同,各有各的优劣。Spring Security是为基于Spring的应用程序提供声明式安全保护的安全性框架,它提供了完整的安全性解决方案,能够在web请求级别和方法调用级别处理身份证验证和授权。因为基于Spring框架,所以Spring Security充分利用了依赖注入和面向切面的技术。web请求级别:使用Servlet规范中的过滤器(Filter)保护Web请求并限制URL级别的访问。方法调用级别。 阅读详情

相关推荐

SAP采购订单行项目增强实战:用BADI ME_GUI_PO_CUST添加自定义字段(避坑指南)

本文详细解析了如何通过BADI ME_GUI_PO_CUST在SAP采购订单行项目中添加自定义字段,包括技术架构理解、字段扩展步骤、自定义函数组创建及BADI实现。文章特别强调了避开官方文档未提及的陷阱,如字段映射限制和屏幕显示问题,并提供了高级优化技巧和性能建议。

weixin_30402343的博客 595

SpringSecurity框架

Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。提供了完善的认证机制和方法级的授权功能。是一款非常优秀的权限管理框架。它的核心是一组过滤器链,不同的功能经由不同的过滤器。这篇文章就是想通过一个小案例将Spring Security整合到SpringBoot中去。要实现的功能就是在认证服务器上登录,然后获取Token,再访问资源服务器中的资源。 对比Shiro框架来说,配置会更复杂一些,但功能更强大,Shrio安全框架上手快,配置简单。本次项目包含了:redis,mybat

Mr_Jin的博客 5609

【Unity Animation 2D】从零到一:骨骼绑定与IK动画实战指南

本文详细介绍了Unity中2D骨骼绑定与IK动画的实战流程,从角色素材准备、骨骼系统创建到权重绘制和IK设置,逐步指导开发者掌握2D动画制作技巧。通过反向动力学(IK)技术,实现更自然的角色动画效果,适用于游戏开发和动画制作。

weixin_30430677的博客 372

SpringSecurity安全权限框架及其原理

首先创建最基本的SpringBoot项目,默认都会。主要是引入依赖和创建Controller进行测试。上述代码为依赖的引入。然后随便写一个controller,写上一个对应的接口,然后直接去浏览器访问。就会发现跳转到了这个登录页面,这个页面也就是Spring Security的默认登陆页面。如果访问很慢,就bootstrap.min.css这个静态资源加载不出来,换个网络即可。

想看什么文章都可以私信给我,综合性博客。 1346

冗余位技术在SAR ADC中的动态误差恢复机制解析

本文深入解析了冗余位技术在SAR ADC中的动态误差恢复机制,详细介绍了其基本概念、动态误差产生原因及冗余位的容错空间设计、时序松弛策略和数字校正算法。通过实际电路设计案例和数学建模,展示了冗余位技术如何显著提升ADC的精度和能效比,同时探讨了未来发展方向。

weixin_28335283的博客 975

C# 开发 ACS 运动控制系统:从入门到高阶应用实践

起始位置</param>/// <param name="endPos">结束位置</param>/// <param name="maxVelocity">最大速度</param>/// <param name="maxAcceleration">最大加速度</param>/// <param name="maxJerk">最大加加速度

品质生活,极致编程。 2842

SpringSecurity安全框架

springSecurity安全框架,连接数据库,将用户权限与资源绑定

优快云lele666的博客 1541

从养虾到退坑:OpenClaw 卸载不留残留,一步到位

文章摘要: 本文提供OpenClaw软件的完整卸载指南,适用于Windows、macOS和Linux系统。内容包含卸载前的数据备份步骤(配置文件、日志、插件列表),以及详细的卸载脚本。Windows版通过批处理文件删除程序文件、注册表项和环境变量;macOS/Linux版则提供shell脚本,涵盖服务停止、软件包卸载、配置清理等步骤。特别强调要删除所有用户数据(包括多用户环境),确保系统无残留。文末建议重启计算机以使更改生效,实现"一步到位"的彻底卸载。

一键难忘的博客 298

Spring Security 基本介绍及基础项目搭建

Spring 是非常流行和成功的 Java 应用开发框架,Spring Security 正是 Spring 家族中的 成员。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方 案。正如你可能知道的关于安全方面的两个主要区域是“认证”和“授权”(或者访问控 制),一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权 (Authorization)两个部分,这两点也是 Spring Security 重要核心功能。

一个菜鸡的博客 2万+

Transformers 实战修炼与源码剖析专栏大纲

本专栏以 Hugging Face Transformers 为主线,围绕“能用、会调、敢上线、懂源码”四个目标展开。内容不把理论堆成公式墙,而是用真实或拟真的业务场景驱动:客服分类、合同抽取、知识库问答、模型微调、推理服务、监控告警、源码扩展等。采用“业务痛点 → 三人剧本对话 → 代码实战 → 总结思考”的四段式结构,让读者在动手完成一个个小项目的过程中,逐步理解 Tokenizer、Model、Pipeline、Trainer、Generation、PEFT、Accelerate、Serving等概念

davidwang456的专栏 923

高速特征金字塔多角度旋转模板匹配(工业零部件缺陷检测C++ Opencv版)

博主在性能较好的笔记本上测试算法全部执行效果大约为45ms,在一般配置的笔记本上博主在性能较好的笔记本上测试算法全部执行效果大约为130ms。下图即为实际检测效果。本文最后附有完整代码:Qt版和MFC版本(可直接运行)。...

认真努力,做一只会飞的毛毛虫。 5547

Java后台框架篇--Springsecurity(二)

剩下的页面代码 本来想给这个demo的源码出来的,但是笔者觉得,通过这个教程一步一步读下来,并自己敲一遍代码,会比直接运行一遍demo印象更深刻,并且更容易理解里面的原理。 而且我的源码其实都公布出来了: login.jsp: 1 2 3 4 5 6 7 8 9 10 11

非淡泊无以明志,非宁静无以致远 964

HDOCK 蛋白蛋白对接软件使用;LZerD、pyDock、ClusPro网页在线对接

参考:hdock支持蛋白与蛋白,也支持蛋白与核酸对接计算。

weixin_42357472的博客 1万+

SpringSecurity框架【详解】

SpringSecurity 文章目录SpringSecurity1、概述2、Spring Security、Apache Shiro 选择问题2.1、Shiro2.1.1、shiro的优点2.1.2、shiro的缺点2.2、Spring Security2.2.1、spring-security的优点3、快速入门3.1、装备工作4、认证4.1、登录流程校验4.2、入门案例的原理4.3、正式开始4.3.1 准备工作4.3.2、实现4.3.3、核心代码实现4.3.3.1、密码加密存储4.3.3.2、登陆接口4

... 9万+

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Java 之SpringBoot+SpringSecurity+Vue实现后台管理系统的开发【一、前端】

一、前端项目搭建 1、项目初始化 安装 vue可视化 npm install --g vue-cli 打开vue的的可视化管理工具页面 vue ui 访问该地址: 访问成功 使用Hbuilder打开项目 2、实现相关依赖的安装 安装 element-ui yarn add element-ui 安装成功 引入element-ui import Vue from 'vue' import App from './App.vue' import router from './r

程序员猫爪 7982

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

安全框架SpringSecurity实战总结(一)

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

FlyingFish868的博客 6893

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

SpringSecurity安全管理框架-(一)初识SpringSecurity

Spring Security是Spring家族中的一个安全管理框架。相比与另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富;Spring Security是一个的框架。它是用于保护基于Spring的应用程序的实际标准;Spring Security是一个框架,致力于为Java应用程序提供身份验证和授权。与所有Spring项目一样,SpringSecurity的真正强大之处在于可以轻松扩展以满足自定义要求。

2301_79351943的博客 1117

SpringSecurity 实战项目(一)

文章目录SpringSecurity 验证帐号密码security认证过程:[《Spring Security认证过程》](https://blog.youkuaiyun.com/weixin_38927257/article/details/102960752) 本文使用springboot+mybatis+SpringSecurity 实现用户权限数据库管理 实现用户和角色用数据库存储,而资源(url)和...

weixin_38927257的博客 5769

SpringSecurity(一)前言以及框架介绍

本节将讨论Spring Security和Spring家族的联系,通过官网可以得知,Spring Security被描述为一种用于身份验证和访问控制的强大且高度可定制的框架,简言之,它就是一个极大简化了的让Spring程序具备安全性保障的框架。你可以在获得其源码。如果要使用Spring Security,至少需要Java 8.

学习不止境的博客 2357

ruoyi若依框架SpringSecurity实现分析

分析一下ruoyi-vue若依中是如何实现认证授权的。在ruoyi-vue若依框架中使用到了SpringSecurity作为认证授权的技术栈。

m0_63837020的博客 5620

【SpringSecurity】认证与鉴权框架SpringSecurity——授权

认证与鉴权框架SpringSecurity——授权

低调做人,低调编码,神码都是浮云 1957

java安全框架有哪些_Java领域最安全框架,SpringSecurity实战教程

spring security 简介SpringSecurity是一个强大且高度可定制的安全框架,致力于为Java应用提供身份认证和授权。 spring security 的核心功能主要包括:认证 (你是谁)授权 (你能干什么)攻击防护 (防止伪造身份) 其核心就是一组过滤器链,项目启动后将会自动配置。最核心的就是 Basic Authentication Filter 用来认证用户的身份,一个在...

weixin_32304839的博客 3360

springSecurity(一):认识springSecurity的过滤器链

springSecurity学习笔记

qq_43586337的博客 1620

一、SpringSecurity框架介绍及入门案例

一、SpringSecurity框架简介 1.1、概要 Spring是非常流行和成功的Java应用开发框架,Spring Security正式Spring家族中的成员。Spring Security基于Spring框架,提供了一套web应用安全性的完整解决方案。 正如你可能知道的关于安全方面的两个主要区域是“认证”和“授权”(或者访问控制),一般来说,web应用的安全性包括用户认证(Authentication)和用户授权(Authorization) 两个部分,这两点也是Spring Security重要

付之一笑的专栏 386

深入浅出SpringSecurity和OAuth2(一)—— 初识SpringSecurity

文章目录前言正文1. 初识SpringSecurity2. Spring Security项目核心jar包介绍3. SpringSecurity核心注解3.1 @EnableWebSecurity3.2 @EnableGlobalMethodSecurity总结参考 前言 相信了解过SpringSecurity或者是OAuth2的读者,会发现网上会有非常多的相关文章,或是纯概念的,或是带有demo的,无论是哪种类型的文章,本人去阅读之后,对于整个框架的概念还是一知半解,也仅仅是实现了某些功能、某些效果而已,

你要悄悄的拔尖,然后惊艳所有人 3435
上一篇: Java后台框架篇--Spring之WebService入门
下一篇: Java后台框架篇--Springsecurity(二)
咸鱼的梦想
博客等级 码龄11年 99粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值