`

spring security验证流程

阅读更多
工作需要,又弄起了权限的管理。虽然很早以前都了解过基于容器的权限实现方式,但是一直都觉得那东西太简陋了。后来使用liferay时发现它的权限系统的确做得很优秀,感觉这也可能是它做得最出色的地方吧。但是当时只停留在怎么使用及一些与其衔接的关系之上,并没有对其底层进行了解,新到现在的公司后,发现这一课还是得补上。但是令人惊讶的是,目前可用的选择并不多,甚至很少,最有名的当属spring security了,虽然很有名,但是关于这方面的资料并不是很多,应用示例就更少了。还好有中文的官方文档与http://www.family168.com/bbs/发布的简要教程,因此学起来不至于太困难。然后参照了一篇downpour写的spring security文章,因此勉强熟悉了spring security的应用开发,但是基本只停留在勉强会用的基础之上,而且还花了本人不少时间,在一个项目的运用中,自己更是差点没下得了台,惊出了一身冷汗。当时的感觉spring security就是个垃圾东西,运用很复杂,哪怕是做一个只拦截路径的权限系统,也要经过很多步骤。现在熟悉了它的一些流程后,虽然不知道这样的实现方式是否是最合理的,但是的确也有它的道理。现在利用放假期间,可以静下心来,理解一些以前让自己迷惑的东西了。downpour牛人的那篇文章讲得很好,以至于本人着实花了点时间才把它完全熟悉,当前自己以前对acegi并不熟悉。熟悉了那篇文章后,还是有些地方让自己不太理解,其中之一就是spring security是怎样完成用户角色权限验证的。下面就对这人问题进行简单的介绍:

首先这篇文章是基于downpour那篇文章的,其地址为:
http://www.iteye.com/topic/319965

最先着手就是配置文件,这也是整个spring security最重要的入口点:

............
<!--  处理国际化信息 -->
	<beans:bean id="authenticationManager"
		class="org.springframework.security.providers.ProviderManager">
		<beans:property name="messageSource" ref="messageSource" />
	</beans:bean>
	
	<beans:bean id="messageSource"
		class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
		<beans:property name="basename"
			value="classpath:org/springframework/security/messages_zh_CN" />
	</beans:bean>

	<authentication-provider user-service-ref="securityManager">
		<password-encoder hash="md5" />
	</authentication-provider>

<!-- AffirmativeBased表示只要有一个Voter通过权限要求,就可以访问 -->
	<beans:bean id="accessDecisionManager"
		class="org.springframework.security.vote.AffirmativeBased">
		<!-- 是否允许所有的投票者弃权,如果为false,表示如果所有的投票者弃权,就禁止访问 -->
		<beans:property name="allowIfAllAbstainDecisions"
			value="false" />
		<beans:property name="decisionVoters">
			<beans:list>
<!-- RoleVoter默认角色名称都要以ROLE_开头,否则不会被计入权限控制,如果要修改前缀,可以通过对rolePrefix属性进行修改 -->
				<beans:bean class="org.springframework.security.vote.RoleVoter" />
				<beans:bean class="org.springframework.security.vote.AuthenticatedVoter" />
			</beans:list>
		</beans:property>
	</beans:bean>

	<beans:bean id="resourceSecurityInterceptor"
		class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
		<beans:property name="authenticationManager" ref="authenticationManager" />
		<beans:property name="accessDecisionManager" ref="accessDecisionManager" />
		<beans:property name="objectDefinitionSource"
			ref="secureResourceFilterInvocationDefinitionSource" />
			<!-- 每次请求都进行检查,如果设为true,则只第一次检查,默认为true -->
		<beans:property name="observeOncePerRequest" value="false" />
		<custom-filter after="LAST" />
	</beans:bean>

	<beans:bean id="secureResourceFilterInvocationDefinitionSource"
		class="com.javaeye.sample.security.interceptor.SecureResourceFilterInvocationDefinitionSource" />
....


上面的“accessDecisionManager”就是切入点,首先需要说明的是,在验证用户是否能通过验证时,spring security提供了三种策略,分别对应那个策略类:
UnanimousBased.java 只要有一个Voter不能完全通过权限要求,就禁止访问。
AffirmativeBased.java只要有一个Voter可以通过权限要求,就可以访问。
ConsensusBased.java只要通过的Voter比禁止的Voter数目多就可以访问了。

在此说一点,ConsensusBased这个类有点特别,如果通过的票数与禁止的票数相同怎么办?
这个类有个allowIfEqualGrantedDeniedDecisions属性,默认为true,关键代码:

if ((grant == deny) && (grant != 0)) {
            if (this.allowIfEqualGrantedDeniedDecisions) {
                return;
            } else {
                throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied",
                        "Access is denied"));
            }
        }


上面的代码表示如果allowIfEqualGrantedDeniedDecisions为true而且通过的票数不为0就授权访问。

在提供好验证策略以后,继续关注其是怎么进行验证的。在上面的XML文件中,accessDescisionManager有个allowIfAllAbstainDecisions属性,这个属性的默认值为false,作用见注释处。现在主要关注的是其decisionVoters属性,中文的理解就是投票,RoleVoter.java 主要作用就是完成角色的投票验证,需要注意的是,它验证的角色,名称必须以ROLE_开头,当然这也可以通过配置文件改变,如:

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


至于RoleVoter是如何完成验证的呆会再说,先回顾一下com.javaeye.sample.security.interceptor.SecureResourceFilterInvocationDefinitionSource:

.....
    public ConfigAttributeDefinition getAttributes(Object filter) throws IllegalArgumentException {
        
        FilterInvocation filterInvocation = (FilterInvocation) filter;
        String requestURI = filterInvocation.getRequestUrl();
        Map<String, String> urlAuthorities = this.getUrlAuthorities(filterInvocation);
        
        String grantedAuthorities = null;
        for(Iterator<Map.Entry<String, String>> iter = urlAuthorities.entrySet().iterator(); iter.hasNext();) {
            Map.Entry<String, String> entry = iter.next();
            
            //url表示从资源表取出的值,在这里代表的是相应的URL
            String url = entry.getKey();
            
            //这段代码表示数据库内的需要验证的资源URL与当前请求的URL相匹配时进行验证
            if(urlMatcher.pathMatchesUrl(url, requestURI)) {
            	//grantedAuthorities表示每个资源对应的角色,如果有多个角色,则以','隔开
                grantedAuthorities = entry.getValue();
                break;
            }
        }
        
        if(grantedAuthorities != null) {
            ConfigAttributeEditor configAttrEditor = new ConfigAttributeEditor();
            configAttrEditor.setAsText(grantedAuthorities);
            return (ConfigAttributeDefinition) configAttrEditor.getValue();
        }
        return null;
    }
....


虽然不重要,但是还是有必要引用一下:

引用

处于继承树顶端的AbstractSecurityInterceptor有三个实现类:

FilterSecurityInterceptor,负责处理FilterInvocation,实现对URL资源的拦截。
MethodSecurityInterceptor,负责处理MethodInvocation,实现对方法调用的拦截。
AspectJSecurityInterceptor,负责处理JoinPoint,主要也是用于对方法调用的拦截。

为了限制用户访问被保护资源,Spring Security提供了一套元数据,用于定义被保护资源的访问权限,这套元数据主要体现为ConfigAttribute和ConfigAttributeDefinition。每个ConfigAttribute中只包含一个字符串,而一个ConfigAttributeDefinition中可以包含多个ConfigAttribute。对于系统来说,每个被保护资源都将对应一个ConfigAttributeDefinition,这个ConfigAttributeDefinition中包含的多个ConfigAttribute就是访问该资源所需的权限。

实际应用中,ConfigAttributeDefinition会保存在ObjectDefinitionSource中,这是一个主要接口,FilterSecurityInterceptor所需的DefaultFilterInvocationDefinitionSource和MethodSecurityInterceptor所需的MethodDefinitionAttributes都实现了这个接口。ObjectDefinitionSource可以看做是Spring Security中权限配置的源头,框架内部所有的验证组件都是从ObjectDefintionSource中获得数据,来对被保护资源进行权限控制的。

为了从xml中将用户配置的访问权限转换成ObjectDefinitionSource类型的对象,Spring Security专门扩展了Spring中提供的PropertyEditor实现了ConfigAttributeEditor,它可以把以逗号分隔的一系列字符串转换成包含多个ConfigAttribute的ConfigAttributeDefintion对象。

"ROLE_ADMIN,ROLE_USER"



ConfigAttributeDefinition
  ConfigAttribute["ROLE_ADMIN"]
  ConfigAttribute["ROLE_USER"]
       
对于FilterSecurityInterceptor来说,最终生成的就是一个包含了url pattern和ConfigAttributeConfiguration的ObjectDefinitionSource。


<intercept-url pattern="/admin.jsp" access="ROLE_ADMIN,ROLE_USER" />



                    ConfigAttributeDefinition
"/admin.jsp"   →     ConfigAttribute["ROLE_ADMIN"]
                      ConfigAttribute["ROLE_USER"]
       
换而言之,无论我们将权限配置的原始数据保存在什么地方,只要最终可以将其转换为ObjectDefintionSource就可以提供给验证组件进行调用,实现权限控制。



当时一直不明白这个getAttributes到底拿来做什么的。下面一步步进行追终,通过配置文件可知,这个类首先会到org.springframework.security.intercept.web.FilterSecurityInterceptor这个类中,这个类有个主要的方法:

 public void invoke(FilterInvocation fi) throws IOException, ServletException {
        if ((fi.getRequest() != null) && (fi.getRequest().getAttribute(FILTER_APPLIED) != null)
            && observeOncePerRequest) {
            // filter already applied to this request and user wants us to observce
            // once-per-request handling, so don't re-do security checking
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        } else {
            // first time this request being called, so perform security checking
            if (fi.getRequest() != null) {
                fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);
            }

            InterceptorStatusToken token = super.beforeInvocation(fi);

            try {
                fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
            } finally {
                super.afterInvocation(token, null);
            }
        }
    }


在此有两点需要说明,首先是observeOncePerRequest属性,一般情况下保持其默认的true,文档上有说:

/*** 
Indicates whether once-per-request handling will be observed. By default this is <code>true</code>,meaning the <code>FilterSecurityInterceptor</code> will only execute once-per-request. Sometimes users may wishit to execute more than once per request, such as when JSP forwards are being used and filter security is desired on each included fragment of the HTTP request.
*/


其次我们需要关注的重点是FilterSecurityInterceptor的超类AbstractSecurityInterceptor的beforeInvocation方法,下面贴出这个类中我们最需要关注的代码:

protected InterceptorStatusToken beforeInvocation(Object object) {
        Assert.notNull(object, "Object was null");

        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());
        }

        ConfigAttributeDefinition attr = this.obtainObjectDefinitionSource().getAttributes(object);

        if (attr == null) {
            if (rejectPublicInvocations) {
                throw new IllegalArgumentException(
                        "No public invocations are allowed via this AbstractSecurityInterceptor. "
                                + "This indicates a configuration error because the "
                                + "AbstractSecurityInterceptor.rejectPublicInvocations property is set to 'true'");
            }

            if (logger.isDebugEnabled()) {
                logger.debug("Public object - authentication not attempted");
            }

            publishEvent(new PublicInvocationEvent(object));

            return null; // no further work post-invocation
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Secure object: " + object + "; ConfigAttributes: " + attr);
        }

        if (SecurityContextHolder.getContext().getAuthentication() == null) {
            credentialsNotFound(messages.getMessage("AbstractSecurityInterceptor.authenticationNotFound",
                    "An Authentication object was not found in the SecurityContext"), object, attr);
        }

        Authentication authenticated = authenticateIfRequired();

        // Attempt authorization
        try {
            this.accessDecisionManager.decide(authenticated, object, attr);
        }
        catch (AccessDeniedException accessDeniedException) {
            AuthorizationFailureEvent event = new AuthorizationFailureEvent(object, attr, authenticated,
                    accessDeniedException);
            publishEvent(event);

            throw accessDeniedException;
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Authorization successful");
        }

        AuthorizedEvent event = new AuthorizedEvent(object, attr, authenticated);
        publishEvent(event);

        // Attempt to run as a different user
        Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attr);

        if (runAs == null) {
            if (logger.isDebugEnabled()) {
                logger.debug("RunAsManager did not change Authentication object");
            }

            // no further work post-invocation
            return new InterceptorStatusToken(authenticated, false, attr, object);
        } else {
            if (logger.isDebugEnabled()) {
                logger.debug("Switching to RunAs Authentication: " + runAs);
            }

            SecurityContextHolder.getContext().setAuthentication(runAs);

            // revert to token.Authenticated post-invocation
            return new InterceptorStatusToken(authenticated, true, attr, object);
        }
    }

    /**
     * Checks the current authentication token and passes it to the AuthenticationManager if
     * {@link org.springframework.security.Authentication#isAuthenticated()} returns false or the property
     * <tt>alwaysReauthenticate</tt> has been set to true.
     *
     * @return an authenticated <tt>Authentication</tt> object.
     */
    private Authentication authenticateIfRequired() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if (authentication.isAuthenticated() && !alwaysReauthenticate) {
            if (logger.isDebugEnabled()) {
                logger.debug("Previously Authenticated: " + authentication);
            }

            return authentication;
        }


上面的代码首先关注其中的一行代码:

ConfigAttributeDefinition attr = this.obtainObjectDefinitionSource().getAttributes(object);


不错,这行代码就是SecureResourceFilterInvocationDefinitionSource存在的主要目的,它主要提供URL与ROLE这两个东西,至于需要验证的用户来源,上面有句代码:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();


众所周知,用户登陆成功后,可以通过:

(User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();


上面的代码可以获取当前登陆的用户的基本信息,所以验证时需要它也很自然的。既然所需要的东西都具备了,下面就讲讲该怎么验证的问题了。在上面的AbstractSecurityInterceptor内,有句代码:
this.accessDecisionManager.decide(authenticated, object, attr);


上面这个accessDecisionManager就是最开始讲的那个accessDecisionManager,终于回到原来的问题上了,由于上面的配置文件中使用了AffirmativeBased投票策略,下面就直接进入此类的decide方法:
public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config)
        throws AccessDeniedException {
        Iterator iter = this.getDecisionVoters().iterator();
        int deny = 0;

        while (iter.hasNext()) {
            AccessDecisionVoter voter = (AccessDecisionVoter) iter.next();
            int result = voter.vote(authentication, object, config);

            switch (result) {
            case AccessDecisionVoter.ACCESS_GRANTED:
                return;

            case AccessDecisionVoter.ACCESS_DENIED:
                deny++;

                break;

            default:
                break;
            }
        }

        if (deny > 0) {
            throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied",
                    "Access is denied"));
        }

        // To get this far, every AccessDecisionVoter abstained
        checkAllowIfAllAbstainDecisions();
    }


这个方法主要有三个作用,第一作用就是完成投票,第二就是验证,从上面的switch与if语句可以看出,只要有一个投票者赞成,就直接返回,验证通过。如果没有一个投票者赞成(弃权)而且有人反对,deny++,到if(deny>0)时扔出异常,最后禁止访问。最后一句

//到这步时,所有的投票者都弃权了
// To get this far, every AccessDecisionVoter abstained
        checkAllowIfAllAbstainDecisions();


这就到了allowIfAllAbstainDecisions属性起作用的时候了。下面就来讲讲AffirmativeBased中用到的投票类RoleVoter,这个类主要工作就是完成投票工作,然后将结果反馈给AffirmativeBased,下面列出RoleVoter的代码:

public class RoleVoter implements AccessDecisionVoter {
    //~ Instance fields ================================================================================================

    private String rolePrefix = "ROLE_";

    //~ Methods ========================================================================================================

    public String getRolePrefix() {
        return rolePrefix;
    }

    /**
     * Allows the default role prefix of <code>ROLE_</code> to be overridden.
     * May be set to an empty value, although this is usually not desirable.
     *
     * @param rolePrefix the new prefix
     */
    public void setRolePrefix(String rolePrefix) {
        this.rolePrefix = rolePrefix;
    }

    public boolean supports(ConfigAttribute attribute) {
        if ((attribute.getAttribute() != null) && attribute.getAttribute().startsWith(getRolePrefix())) {
            return true;
        }
        else {
            return false;
        }
    }

    /**
     * This implementation supports any type of class, because it does not query
     * the presented secure object.
     *
     * @param clazz the secure object
     *
     * @return always <code>true</code>
     */
    public boolean supports(Class clazz) {
        return true;
    }

    public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {
        int result = ACCESS_ABSTAIN;
        Iterator iter = config.getConfigAttributes().iterator();
        GrantedAuthority[] authorities = extractAuthorities(authentication);        

        while (iter.hasNext()) {
            ConfigAttribute attribute = (ConfigAttribute) iter.next();

            if (this.supports(attribute)) {
                result = ACCESS_DENIED;

                // Attempt to find a matching granted authority
                for (int i = 0; i < authorities.length; i++) {
                    if (attribute.getAttribute().equals(authorities[i].getAuthority())) {
                        return ACCESS_GRANTED;
                    }
                }
            }
        }

        return result;
    }
    
    GrantedAuthority[] extractAuthorities(Authentication authentication) {
    	return authentication.getAuthorities();
    }
}


这个类中最重要的代码就是这句:

if (attribute.getAttribute().equals(authorities[i].getAuthority())) {
                        return ACCESS_GRANTED;
                    }


这句代码的意思就是把SecureResourceFilterInvocationDefinitionSource传入的角色名称与SecurityContextHolder.getContext().getAuthentication()传入的用户所拥有的角色的角色名称相比较,如果相等则通过验证。

在配置文件中还用到了一个投票类AuthenticatedVoter,这个类与RoleVoter属于同级,RoleVoter用来验证角色,那AutherticatedVoter又是用来干什么的呢?
这个类完整代码:

public class AuthenticatedVoter implements AccessDecisionVoter {
    //~ Static fields/initializers =====================================================================================

    public static final String IS_AUTHENTICATED_FULLY = "IS_AUTHENTICATED_FULLY";
    public static final String IS_AUTHENTICATED_REMEMBERED = "IS_AUTHENTICATED_REMEMBERED";
    public static final String IS_AUTHENTICATED_ANONYMOUSLY = "IS_AUTHENTICATED_ANONYMOUSLY";
    //~ Instance fields ================================================================================================

    private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();

    //~ Methods ========================================================================================================

    private boolean isFullyAuthenticated(Authentication authentication) {
        return (!authenticationTrustResolver.isAnonymous(authentication)
        && !authenticationTrustResolver.isRememberMe(authentication));
    }

    public void setAuthenticationTrustResolver(AuthenticationTrustResolver authenticationTrustResolver) {
        Assert.notNull(authenticationTrustResolver, "AuthenticationTrustResolver cannot be set to null");
        this.authenticationTrustResolver = authenticationTrustResolver;
    }

    public boolean supports(ConfigAttribute attribute) {
        if ((attribute.getAttribute() != null)
            && (IS_AUTHENTICATED_FULLY.equals(attribute.getAttribute())
            || IS_AUTHENTICATED_REMEMBERED.equals(attribute.getAttribute())
            || IS_AUTHENTICATED_ANONYMOUSLY.equals(attribute.getAttribute()))) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * This implementation supports any type of class, because it does not query the presented secure object.
     *
     * @param clazz the secure object
     *
     * @return always <code>true</code>
     */
    public boolean supports(Class clazz) {
        return true;
    }

    public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {
        int result = ACCESS_ABSTAIN;
        Iterator iter = config.getConfigAttributes().iterator();

        while (iter.hasNext()) {
            ConfigAttribute attribute = (ConfigAttribute) iter.next();

            if (this.supports(attribute)) {
                result = ACCESS_DENIED;

                if (IS_AUTHENTICATED_FULLY.equals(attribute.getAttribute())) {
                    if (isFullyAuthenticated(authentication)) {
                        return ACCESS_GRANTED;
                    }
                }

                if (IS_AUTHENTICATED_REMEMBERED.equals(attribute.getAttribute())) {
                    if (authenticationTrustResolver.isRememberMe(authentication)
                        || isFullyAuthenticated(authentication)) {
                        return ACCESS_GRANTED;
                    }
                }

                if (IS_AUTHENTICATED_ANONYMOUSLY.equals(attribute.getAttribute())) {
                    if (authenticationTrustResolver.isAnonymous(authentication) || isFullyAuthenticated(authentication)
                        || authenticationTrustResolver.isRememberMe(authentication)) {
                        return ACCESS_GRANTED;
                    }
                }
            }
        }

        return result;
    }
}



作用见下面引用:
引用

AuthenticatedVoter用于判断ConfigAttribute上是否拥有IS_AUTHENTICATED_FULLY,IS_AUTHENTICATED_REMEMBERED或IS_AUTHENTICATED_ANONYMOUSLY之类的配置。
如果配置为IS_AUTHENTICATED_FULLY,那么只有AuthenticationTrustResolver的isAnonymous()和isRememberMe()都返回false时才能通过验证。
如果配置为IS_AUTHENTICATED_REMEMBERED,那么会在AuthenticationTrustResolver的isAnonymous()返回false时通过验证。
如果配置为IS_AUTHENTICATED_ANONYMOUSLY,就可以在AuthenticationTrustResolver的isAnonymous()和isRememberMe()两个方法返回任意值时都可以通过验证。


其中上面引用中的ConfigAttribute就是指SecureResourceFilterInvocationDefinitionSource的getAttributes()方法中ConfigAttributeDefinition中的ConfigAttribute,downpour的文章只是传入了ROLE_USER,ROLE_ADMIN等内容,要想让AuthenticatedVoter有用武之地,可以传入
IS_AUTHENTICATED_FULLY、IS_AUTHENTICATED_REMEMBERED、IS_AUTHENTICATED_ANONYMOUSLY中的值。

需要注意的是AffirmativeBased中遍历的投票者是要分先后的,也就是说RoleVoter在AuthenticatedVoter前面的话,会先进行RoleVoter验证,如果RoleVoter投票未通过,再进行了AuthenticatedVoter投票。

这样spring security的验证流程就基本清楚了,当然这篇文章也还是有些地方讲得不完善,以事有时间再来修改。
分享到:
评论
7 楼 BigHanson 2016-09-09  
写得非常棒,醍醐灌顶   可以转发吗
6 楼 背后的光 2016-03-05  
         
5 楼 leon709 2011-12-08  
深入了,强大
4 楼 gccr 2011-02-18  
花了好几天整SpringSecurity.今天才算是给搭起来.
既然楼主出了这样的文件,我就不用再去看源码了.多谢楼主了.
明天好好研究一下楼主的文章.
3 楼 faithfighting 2010-09-30  
springsecurity的文章很少,有这么好的学习资料,没人顶起真的可惜。我这段时间正在学这个框架,感觉学起来还真的是麻烦~
2 楼 fansofjava 2010-06-20  
说来惭愧,做了一段时间后,本想研究一下acl的,但发现精力跟不上了,对java这东西是没什么兴趣了,也就没怎么去看了。
1 楼 shuiguozheng 2010-06-20  
这么好的文章,怎么没人顶了!  和楼主一样,我也是做权限管理的,专做会员管理,希望能多多交流。之前权限都是通过公司封装的一个工具实现的,源码也没有看到,呵呵,现在对ss3开始痴迷了, 我qq是279737094 欢迎加我!

相关推荐

    Spring Security验证流程剖析及自定义验证方法

    Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。这篇文章主要介绍了Spring Security验证流程剖析及自定义验证方法,需要的朋友可以参考下

    浅析Spring Security登录验证流程

    主要介绍了Spring Security登录验证流程源码解析,本文结合源码讲解登录验证流程,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下

    spring security 参考手册中文版

    Spring Security 参考 1 第一部分前言 15 1.入门 16 2.介绍 17 2.1什么是Spring Security? 17 2.2历史 19 2.3版本编号 20 2.4获得Spring安全 21 2.4.1使用Maven 21 Maven仓库 21 Spring框架 22 2.4.2 Gradle 23 ...

    Spring-Boot结合Security+JWT 简单实现前后端分离用户登录、授权案例

    Spring-Security结合JWT 实现前后端分离完成权限验证功能案例,案例中,主要完成用户登录获取Token,通过Token访问Rest接口,没有权限或授权失败时返回JSON,前端根据状态码进行重新登录;案例中的用户名称: jake_j...

    Springboot整合Spring security+Oauth2+JWT搭建认证服务器,网关,微服务之间权限认证及授权

    Springboot整合Spring security+Oauth2+JWT搭建认证服务器,网关,微服务之间权限认证及授权。 OAuth2是一个关于授权的开放标准,核心思路是通过各类认证手段(具体什么手段OAuth2不关心)认证用户身份,并颁发...

    SpringSecurity 3.0.1.RELEASE.CHM

    5.5. Spring Security中的访问控制(验证) 5.5.1. 安全和AOP建议 5.5.2. 安全对象和AbstractSecurityInterceptor 5.5.2.1. 配置属性是什么? 5.5.2.2. RunAsManager 5.5.2.3. AfterInvocationManager 5.5.2.4...

    Spring Security-3.0.1中文官方文档(翻译版)

    5.5. Spring Security 中的访问控制(验证) 5.5.1. 安全和AOP 建议 5.5.2. 安全对象和AbstractSecurityInterceptor 5.5.2.1. 配置属性是什么? 5.5.2.2. RunAsManager 5.5.2.3. AfterInvocationManager ...

    spring security 登录、权限管理配置

    登录流程 1)容器启动(MySecurityMetadataSource:loadResourceDefine加载系统资源与权限列表) 2)用户发出请求 3)过滤器拦截(MySecurityFilter:doFilter) 4)取得请求资源所需权限(MySecurityMetadataSource:...

    Spring Security 中文教程.pdf

    5.5. Spring Security中的访问控制(验证) 5.5.1. 安全和AOP建议 5.5.2. 安全对象和AbstractSecurityInterceptor 5.5.2.1. 配置属性是什么? 5.5.2.2. RunAsManager 5.5.2.3. AfterInvocationManager ...

    springboot-springsecurity-jwt-demo

    这两行,将我们定义的JWT方法加入SpringSecurity的处理流程中。 四:简单测试 下面对我们的程序进行简单的验证: 1.请求获取用户列表接口:http://localhost:8080/users/userList接口,会收到403错误 { ...

    spring-security-multi-auth:Spring Boot应用程序示例,演示用于多种身份验证的Spring Security Java配置(Siteminder SSO +表单登录)

    Spring Security多身份验证展示柜基于Spring Boot的示例应用程序,展示了用于多个身份验证流程的案例Java配置-Siteminder SSO和基于表单的登录。入门/运行应用程序克隆存储库,使用maven将其打包为jar,然后从目标...

    spring-boot-security-postgresql:Spring Boot,Spring Security,PostgreSQL

    Spring Boot,Spring Security,PostgreSQL:JWT身份验证和授权示例 用户注册,用户登录和授权过程。 该图显示了我们如何实现用户注册,用户登录和授权过程的流程。 具有Spring Security的Spring Boot服务器架构 您...

    Spring认证考试流程

    Spring Professional认证旨在测试和验证学生对 Spring 和 Spring Boot核心方面的理解和熟悉程度,例如:配置、组件扫描、AOP、数据访问和事务、REST、安全、自动配置、执行器、 Spring boot测试等。 认证对象: - ...

    spring-boot-spring-security-jwt-authentication:Spring Boot + Security:基于令牌的身份验证示例,具有JWT,授权,Spring Data和MySQL

    使用Spring Security和Spring Data JPA的Spring Boot JWT身份验证示例用户注册,用户登录和授权过程。 该图显示了我们如何实现用户注册,用户登录和授权过程的流程。具有Spring Security的Spring Boot服务器架构您...

    SpringbootSecurity

    使用Spring Security和Spring Data JPA的Spring Boot JWT身份验证示例 用户注册,用户登录和授权过程。 该图显示了我们如何实现用户注册,用户登录和授权过程的流程。 具有Spring Security的Spring Boot服务器架构 ...

    开源框架 Spring Gossip

    Resource 的取得 解析文字讯息 倾听事件 事件传播 &lt;br&gt; AOP(Aspect-Oriented Programming) 在一个服务的流程中插入与服务无关的逻辑(例如Logging、Security),这样的逻辑称为 Cross...

    Spring攻略(第二版 中文高清版).part1

    第5章 Spring Security 164 5.1 加强URL访问安全 165 5.1.1 问题 165 5.1.2 解决方案 165 5.1.3 工作原理 166 5.2 登录到Web应用 175 5.2.1 问题 175 5.2.2 解决方案 175 5.2.3 工作原理 175 5.3...

    Spring in Action(第2版)中文版

    7.4.1代理springsecurity的过滤器 7.4.2处理安全上下文 7.4.3提示用户登录 7.4.4处理安全例外 7.4.5强制web安全性 7.4.6确保一个安全的通道 7.5视图层安全 7.5.1有条件地渲染内容 7.5.2显示用户身份验证信息...

    Spring in Action(第二版 中文高清版).part2

    7.4.1 代理Spring Security的过滤器 7.4.2 处理安全上下文 7.4.3 提示用户登录 7.4.4 处理安全例外 7.4.5 强制Web安全性 7.4.6 确保一个安全的通道 7.5 视图层安全 7.5.1 有条件地渲染内容 7.5.2 显示用户...

    Spring in Action(第二版 中文高清版).part1

    7.4.1 代理Spring Security的过滤器 7.4.2 处理安全上下文 7.4.3 提示用户登录 7.4.4 处理安全例外 7.4.5 强制Web安全性 7.4.6 确保一个安全的通道 7.5 视图层安全 7.5.1 有条件地渲染内容 7.5.2 显示用户...

Global site tag (gtag.js) - Google Analytics