`

Spring Security Acegi 学习之路四 (转)

阅读更多

安全对象访问控制

 

 

     Acegi 分别通过 Servlet 过滤器和方法拦截器对 URL 资源和业务方法进行访问拦截,向授权用户开放访问请求拒绝未授权用户的访问。

 

匿名用户权限信息

 

 

     Acegi 引入了一个匿名用户权限的概念,匿名用户权限定义了未登录用户所能访问到的程序资源,这些资源包括站点首页、登录页面、静态资源共享等。 Acegi 为匿名用户认证提供了三个类,它们分别是:

  • AnonymousAuthenticationToken: 该类是 Authentication 的实现类,它保存着匿名用户的权限信息
  • AnonymousAuthenticationProvider: 该类是 AuthenticationProvider 的实现类,它能根据 AnonymousAuthenticationToken 进行匿名用户认证
  • AnonymousProcessingFilter: 该过滤器发现 SecurityContextHolder 中不存在 Authentication 时,自动添加一个 AnonymousAuthenticationToken SecurityContextHolder 中。
applicationContext-acegi-plugin.xml: 匿名用户
Xml代码
  1. < bean   id = "filterChainProxy"   class = "org.acegisecurity.util.FilterChainProxy" >   
  2.        < property   name = "filterInvocationDefinitionSource" >   
  3.             < value >   
  4.                 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON  
  5.                 PATTERN_TYPE_APACHE_ANT  
  6.                /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter, logoutFilter,rememberMeProcessingFilter,anonymousProcessingFilter  
  7.             </ value >   
  8.        </ property >   
  9. </ bean >   
  10. <!--匿名用户处理过滤器 -->   
  11. < bean   id = "anonymousProcessingFilter"   class = "org.acegisecurity.providers.anonymous.AnonymousProcessingFilter" >   
  12.         < property   name = "key"   value = "anonymousUser" />   
  13.         <!--匿名用户用户属性 -->   
  14.         < property   name = "userAttribute"   value = "ANONYMOUSUSER,PRIV_ANONYMOUS" />   
  15. </ bean >   
  16. <!--匿名用户认证提供者 -->   
  17. < bean   id = "anonymousAuthenticationProvider"   
  18. class = "org.acegisecurity.providers. anonymous.AnonymousAuthenticationProvider " >   
  19.         < property   name = "key"   value = "anonymousUser" />   
  20. </ bean >   
  21.   
  22. < bean   id = "authenticationManager"   
  23. class = "org.acegisecurity.providers.ProviderManager" >   
  24.        < property   name = "providers" >   
  25.           < list >   
  26.             …  
  27.            <!--将匿名用户认证提供者添加到认证管理器的列表中 -->   
  28.            < ref   local = " anonymousAuthenticationProvider"   />      
  29.           </ list >   
  30.        </ property >   
  31. </ bean >   
<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
       <property name="filterInvocationDefinitionSource">
            <value>
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                PATTERN_TYPE_APACHE_ANT
               /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter, logoutFilter,rememberMeProcessingFilter,anonymousProcessingFilter
            </value>
       </property>
</bean>
<!--匿名用户处理过滤器 -->
<bean id="anonymousProcessingFilter" class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
        <property name="key" value="anonymousUser"/>
        <!--匿名用户用户属性 -->
        <property name="userAttribute" value="ANONYMOUSUSER,PRIV_ANONYMOUS"/>
</bean>
<!--匿名用户认证提供者 -->
<bean id="anonymousAuthenticationProvider"
class="org.acegisecurity.providers. anonymous.AnonymousAuthenticationProvider ">
        <property name="key" value="anonymousUser"/>
</bean>

<bean id="authenticationManager"
class="org.acegisecurity.providers.ProviderManager">
       <property name="providers">
          <list>
	        …
	       <!--将匿名用户认证提供者添加到认证管理器的列表中 -->
 	       <ref local=" anonymousAuthenticationProvider" />	
          </list>
       </property>
</bean>
 
  URL 资源访问控制

     URL 资源是用户直接通过请求调用的安全对象, Acegi 通过基于 Servlet 过滤器的 FilterSecurityInterceptor 对所有的 URL 资源进行拦截,并施加有效的访问控制。

 

applicationContext-acegi-plugin.xml: URL资源访问控制

Xml代码
  1. < bean   id = "filterChainProxy"   class = "org.acegisecurity.util.FilterChainProxy" >   
  2.        < property   name = "filterInvocationDefinitionSource" >   
  3.            < value >   
  4.                 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON  
  5.                 PATTERN_TYPE_APACHE_ANT  
  6.                 /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,logoutFilter,rememberMeProcessingFilter,anonymousProcessingFilter,filterSecurityInterceptor  
  7.             </ value >   
  8.         </ property >   
  9. </ bean >   
  10.   
  11. <!--URL资源访问拦截器-->   
  12. < bean   id = "filterSecurityInterceptor"   class = "org.acegisecurity.intercept.web.FilterSecurityInterceptor" >   
  13.         < property   name = "authenticationManager"   ref = "authenticationManager" />   
  14.     < property   name = "asscessDecisionManager"   ref = " asscessDecisionManager" />   
  15.     < property   name = "objectDefinitionSource" >   
  16.         < value >   
  17.              CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON  
  18.                      PATTERN_TYPE_APACHE_ANT  
  19.              /login.jsp = PRIV_ANONYMOUS ,PRIV_COMMON  
  20.              /hello_1.jsp = PRIV_1   
  21.              /updateForum.jsp = PRIV_1   
  22.         </ value >   
  23.     </ property >   
  24. </ bean >   
  25. <!--HTTP请求访问决策管理器-->   
  26. < bean   id = "asscessDecisionManager"   class = "org.acegisecurity.vote.AffirmativeBased" >   
  27.     <!--是否所有投票者弃权意即同意-->   
  28.        < property   name = "allowIfAllAbstainDecisions"   value = "true" />   
  29.     <!--投票者列表-->   
  30.     <   property   name = "decisionVoters" >   
  31.         < list >   
  32.                < ref   bean = "roleVoter" />   
  33.         </ list >   
  34.     </ property >   
  35. </ bean >   
  36. < bean   id = "roleVoter"   class = "org.acegisecurity.vote.RoleVoter" >   
  37.     <!--对应的权限前缀-->   
  38.        < property   name = "rolePrefix"   value = "PRIV_" />   
  39. </ bean >   
<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
       <property name="filterInvocationDefinitionSource">
           <value>
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                PATTERN_TYPE_APACHE_ANT
                /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,logoutFilter,rememberMeProcessingFilter,anonymousProcessingFilter,filterSecurityInterceptor
            </value>
        </property>
</bean>

<!--URL资源访问拦截器-->
<bean id="filterSecurityInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
        <property name="authenticationManager" ref="authenticationManager"/>
	<property name="asscessDecisionManager" ref=" asscessDecisionManager"/>
	<property name="objectDefinitionSource">
		<value>
		     CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                     PATTERN_TYPE_APACHE_ANT
		     /login.jsp=PRIV_ANONYMOUS,PRIV_COMMON
		     /hello_1.jsp=PRIV_1
		     /updateForum.jsp=PRIV_1
		</value>
	</property>
</bean>
<!--HTTP请求访问决策管理器-->
<bean id="asscessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
	<!--是否所有投票者弃权意即同意-->
       <property name="allowIfAllAbstainDecisions" value="true"/>
	<!--投票者列表-->
	< property name="decisionVoters">
		<list>
		       <ref bean="roleVoter"/>
		</list>
	</property>
</bean>
<bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter">
	<!--对应的权限前缀-->
       <property name="rolePrefix" value="PRIV_"/>
</bean>
 

 

    拦截器将对所有 URL 请求进行处理:

 

1 .判断用户是否已经通过身份认证,如果未通过身份认证,调用身份认证管理器进行处理,这意味着请求将重定向到登录页面。

2 .如果通过身份认证,调用访问决策管理器判断用户是否有权访问目标的 URL 资源。

3 .访问决策管理器将组织投票者进行投票并根据投票结果给出是否有权访问的结果。

4. 如果无权访问,将招聘异常否则开放目标 URL 资源的访问。

 

    我们定义的 AccessDecisionManager Bean ,它通过组织投票者对是否允许访问进行投票并得到最终的结果。所有投票者都实现 AccessDecisionVoter 接口,决策管理器投票者的 int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) 方法获得投票结果。有三个不同的投票结果:

ACCESS_ABSTAIN: 弃权

ACCESS_DENIED :拒绝

ACCESS_GRANTED :允许

 

    根据不同决策方案, Acegi org.acegisecurity.vote 包中提供了三个 AccessDecisionManager 的实现类:

AffirmativeBased: 有同意票策略

ConsensusBased: 少数服从多数策略

UnanimousBased :无反对票策略

 

 

异常转换过滤器

 

 

    异常转换过滤器( ExceptionTranslationFilter )能够捕捉 Acegi 招聘的抛出的权限访问异常,并导向适合响应页面,大大提高了系统交互的友好性。

注意, exceptionTranslationFilter 必须位于 filterSecurityIntercetor 之前。

 

applicationContext-acegi-plugin.xml:异常转换过滤器

 

Xml代码
  1. < bean   id = "filterChainProxy"   class = "org.acegisecurity.util.FilterChainProxy" >   
  2.         < property   name = "filterInvocationDefinitionSource" >   
  3.             < value >   
  4.                …                 
  5. /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,logoutFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor  
  6.             </ value >   
  7.         </ property >   
  8. </ bean >   
  9.   
  10. < bean   id = "exceptionTranslationFilter"   class = "org.acegisecurity.ui.ExceptionTranslationFilter" >   
  11.     <!--如果是未通过身份认证引发的访问异常,将请求导向到认证入口-->   
  12.        < property   name = "authenticationEntryPoint" >   
  13.         < ref   local = "authenticationEntryPoint" />   
  14.     </ property >   
  15.     <!--越权的访问将导向到出错页面-->   
  16.     < property   name = "asscessDeniedHandler" >   
  17.     < bean   class = "org.acegisecurity.ui.AsscessDeniedHandlerImpl" >   
  18.         < property   name = "errorPage"   value = "/error.jsp" />   
  19.     </ bean >   
  20.     </ property >   
  21. </ bean >   
  22.   
  23. < bean   id = "authenticationEntryPoint"   class = "org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint" >   
  24.        < property   name = "loginFormUrl"   value = "/index.jsp" />   
  25. </ bean >   
<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
        <property name="filterInvocationDefinitionSource">
            <value>
               …               
/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,logoutFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor
            </value>
        </property>
</bean>

<bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
	<!--如果是未通过身份认证引发的访问异常,将请求导向到认证入口-->
       <property name="authenticationEntryPoint">
		<ref local="authenticationEntryPoint"/>
	</property>
	<!--越权的访问将导向到出错页面-->
	<property name="asscessDeniedHandler">
	<bean class="org.acegisecurity.ui.AsscessDeniedHandlerImpl">
		<property name="errorPage" value="/error.jsp"/>
	</bean>
	</property>
</bean>

<bean id="authenticationEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
       <property name="loginFormUrl" value="/index.jsp"/>
</bean>
 

 

        通过 AuthenticationProcessingFilterEntryPoint 学习定义用户登录页面的地址,在抛出 AuthenticationException 异常时,请求导向 index.jsp 登录页面。当抛出 AccessDeniedException 异常时,请求民向到 error.jsp 页面。

 

业务类方法访问控制


    Acegi 为业务类安全对象添加环绕增强的切面,在业务类方法被访问前后就可以进行拦截并实施访问控制, Acegi 提供了两种实施环绕增强切面的方案, Spring AOP和 AspectJ, 这里我们看一下 Spring AOP 方案:


applicationContext-acegi-plugin.xml: 基于 ProxyFactoryBean 的代理

 

Xml代码
  1. < bean   id = "methodSecurityInterceptor"   class = "org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor" >   
  2.    < property   name = "authenticationManager"   ref = "authenticationManager" />   
  3.     < property   name = "asscessDecisionManager"   ref = " asscessDecisionManager" />   
  4.     < property   name = "objectDefinitionSource" >   
  5.         < value >   
  6.             com.ccd.service.BbtForum.updateForum = PRIV_2   
  7.         </ value >   
  8.     </ property >   
  9. </ bean >   
  10.   
  11. < bean   id = "bbtForum"   class = "org.springframework.aop.framework.ProxyFactoryBean" >   
  12.       < property   name = "intercetorNames" >   
  13.         < list >   
  14.             < idref   bean = "methodSecurityInterceptor" />   
  15.         </ list >   
  16.     </ property >   
  17.     < property   name = "proxyTargetClass"   value = "true" />   
  18.     < property   name = "target"   ref = "bbtForumTarget" />   
  19. </ bean >   
  20.   
  21. < bean   id ="bbtForumTarget" class ="com.ccd.service.BbtForum" />   
<bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
   <property name="authenticationManager" ref="authenticationManager"/>
	<property name="asscessDecisionManager" ref=" asscessDecisionManager"/>
	<property name="objectDefinitionSource">
		<value>
			com.ccd.service.BbtForum.updateForum=PRIV_2
		</value>
	</property>
</bean>

<bean id="bbtForum" class="org.springframework.aop.framework.ProxyFactoryBean">
      <property name="intercetorNames">
		<list>
			<idref bean="methodSecurityInterceptor"/>
		</list>
	</property>
	<property name="proxyTargetClass" value="true"/>
	<property name="target" ref="bbtForumTarget"/>
</bean>

<bean id="bbtForumTarget"class="com.ccd.service.BbtForum"/>
 


使用注解提供对象定义源信息


   Acegi 支持通过注解提供对象定义源的无数据信息


Java代码
  1. package  com.ccd.service;  
  2. import  org.acegisecurity.annotation.Secured;  
  3. import  com.ccd.domain.Forum;  
  4.   
  5. public   class  BbtForum{  
  6.     @Secured ({ "PRIV_2" }) //该业务方法对应的权限   
  7.     public   void  updateForum(Forum forum){  
  8.         System.out.println("execute update Forum…" );  
  9.     }  
  10. }  
package com.ccd.service;
import org.acegisecurity.annotation.Secured;
import com.ccd.domain.Forum;

public class BbtForum{
	@Secured({"PRIV_2"})//该业务方法对应的权限
	public void updateForum(Forum forum){
		System.out.println("execute update Forum…");
	}
}

 

    Acegi 通过 MethodDefinitionAttributes 自动扫描 Spring 容器中的 Bean ,获取注解表示对象定义元数据信息

applicationContext-acegi-plugin.xml: 基于注解的对象定义源

 

Xml代码
  1. < bean   id = "methodSecurityInterceptor"   class = "org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor" >   
  2.       < property   name = "authenticationManager"   ref = "authenticationManager" />   
  3.     < property   name = "asscessDecisionManager"   ref = " asscessDecisionManager" />   
  4.     < property   name = "objectDefinitionSource"   ref = "objectDefinitionSource" />   
  5. </ bean >   
  6. <!--根据Bean的注解元数据定义的对象定义源-->   
  7. < bean   id = "objectDefinitionSource"   class = "org.acegisecurity.intercept.method.MethodDefinitionAttributes" >   
  8.     <!--获取@Secured的注解元数据-->   
  9.       < property   name = "attributes" >   
  10.        < bean   class = "org.acegisecurity.annotation.SecurityAnnotationAttributes" >   
  11.       </ property >   
  12. </ bean >   
<bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
      <property name="authenticationManager" ref="authenticationManager"/>
	<property name="asscessDecisionManager" ref=" asscessDecisionManager"/>
	<property name="objectDefinitionSource" ref="objectDefinitionSource"/>
</bean>
<!--根据Bean的注解元数据定义的对象定义源-->
<bean id="objectDefinitionSource" class="org.acegisecurity.intercept.method.MethodDefinitionAttributes">
	<!--获取@Secured的注解元数据-->
      <property name="attributes">
	   <bean class="org.acegisecurity.annotation.SecurityAnnotationAttributes">
      </property>
</bean>

 

     注意, Acegi 也支持 Jakata Commons Attributes 进行标注,这时必须将

 

 

 

Xml代码
  1. < bean   class = "org.acegisecurity.annotation.SecurityAnnotationAttributes" />   
<bean class="org.acegisecurity.annotation.SecurityAnnotationAttributes"/>

 

           替换成

Xml代码
  1. < bean   class = "org.springframework.metadata.commons.CommonsAttributes" />   
<bean class="org.springframework.metadata.commons.CommonsAttributes"/>
 

使用 BeanNameAutoProxyCreator 进行批量代理

 

 

 

applicationContext-acegi-plugin.xml: 通过指定Bean名字进行批量代理

 

Xml代码
  1. < bean   class = "org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" >   
  2.      < property   name = "intercetorNames" >   
  3.         < list >   
  4.             < value > methodSecurityInterceptor </ value >   
  5.         </ list >   
  6.     </ property >   
  7.     < property   name = "beanNames" >   
  8.         < list >   
  9.             < value > bbtForum </ value >   
  10.         </ list >   
  11.     </ property >   
  12. </ bean >   
  13. < bean   id = "bbtForum"   class = "com.ccd.service.BbtForum" >   
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
     <property name="intercetorNames">
		<list>
			<value>methodSecurityInterceptor</value>
		</list>
	</property>
	<property name="beanNames">
		<list>
			<value>bbtForum</value>
		</list>
	</property>
</bean>
<bean id="bbtForum" class="com.ccd.service.BbtForum">
 

 

 

PS:本文主要摘自《精通Spring 2.x ——企业应用开发详解》

分享到:
评论

相关推荐

    spring的acegi应用

    Acegi是Spring早期的一个安全组件,后来发展成为Spring Security,是Spring生态系统中的重要部分,用于提供全面的安全解决方案。 Spring Security(原名Acegi Security)是一个强大的框架,用于保护基于Spring的...

    spring_acegi精彩实例,带MYSQL数据库脚本,保证能运行

    spring_acegi精彩实例,带MYSQL数据库脚本,保证能运行 spring_acegi精彩实例,带MYSQL数据库脚本,保证能运行 spring_acegi精彩实例,带MYSQL数据库脚本,保证能运行 spring_acegi精彩实例,带MYSQL数据库脚本,...

    Spring源代码解析(十):Spring_Acegi框架授权的实现.doc

    在Spring框架中,Acegi(现在已经并入Spring Security)是一个强大的安全管理组件,它提供了认证和授权功能。在本文中,我们将深入探讨Spring_Acegi框架如何实现授权机制,特别是通过`FilterSecurityInterceptor`来...

    Spring Acegi权限控制

    Acegi Security(现已被Spring Security替代)是一个功能强大的安全框架,它主要解决了认证(Authentication)和授权(Authorization)这两个核心的安全问题。 首先,让我们理解认证和授权的基本概念: - **认证**...

    spring security3 中文版本

    Spring Security 的前身是 Acegi Security,它于 2004 年发布。2006 年,Acegi 被集成到 Spring 框架中,并改名为 Spring Security。自此之后,Spring Security 成为了 Spring 生态系统中的一个重要组成部分,不断...

    spring acegi 详细文档

    &lt;bean id="filterSecurityInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"&gt; &lt;sec:filter-security-metadata-source&gt; **" access="ROLE_ADMIN"/&gt; **" access="IS_...

    Spring的ACEGI的应用

    而在安全方面,Spring曾提供了一个名为Acegi Security的模块,它是Spring早期的一个安全解决方案,用于实现复杂的认证和授权需求。本文将深入探讨Spring的Acegi应用及其核心概念。 **1. Acegi Security简介** Acegi...

    spring-security 官方文档 中文版

    Spring Security 最初是由 Luke Taylor 和 Ray Ryan 开发的名为 Acegi Security 的项目,在 2005 年被并入 Spring 项目,并重新命名为 Spring Security。自那时起,Spring Security 经历了多个版本的迭代,不断地...

    spring-security所需要的jar包,

    Acegi Security提供了一套基于Spring的认证和授权机制,但在Spring Security 2.x版本之后,大部分功能已被Spring Security自身所取代。 3. **spring-security-core-tiger-2.0.5.RELEASE-tests.jar**:这是一个测试...

    spring security reference【洋文】

    Spring Security是一个功能强大且可高度定制的身份验证和访问控制...Spring Security Reference作为官方文档,是学习和应用Spring Security的重要资源,建议深入研究以充分利用其提供的功能来增强应用程序的安全性。

    Spring Security 把授权信息写入数据库

    在从Acegi安全框架转换到Spring Security 2.0时,一个重要的变化就是如何将授权信息存储从XML配置文件迁移到数据库。这使得授权策略更加灵活,易于管理和维护。 24.1. Spring Security简介 Spring Security 2.0...

    Spring+Acegi+ehcache安全框架常用jar包.rar

    而Acegi Security(现在已经更名为Spring Security)是Spring生态体系中的一个强大安全组件,用于处理应用程序的安全访问控制。Ehcache则是一个广泛使用的内存缓存系统,它可以帮助提高应用性能,通过缓存数据来减少...

    spring Acegi例子,很简单的一个acegi实例,容易理解

    3. **过滤器安全链(Filter Security Interceptor)**:Acegi的核心组件之一,它是Servlet过滤器,负责拦截请求并根据配置的策略进行身份验证和授权。 4. **安全性配置(Security Configurations)**:在Spring应用...

    Spring Security 中文教程.pdf

    - **发展历程**:Spring Security的发展历程可以追溯到早期的ACEGI Security项目,后来被集成到Spring框架中,并经过多次迭代更新,形成了如今功能强大且灵活的Spring Security框架。 - **获取方式**: - **项目...

    springsecurity官方文档3.2

    - **历史**: 本章节简要回顾了 Spring Security 的发展历程,包括其前身 Acegi 安全框架的历史背景。 - **版本编号**: 明确了 Spring Security 版本的命名规则,例如 `3.2.0.M2` 中的 `.M2` 表示这是一个里程碑版本...

    Spring ACEGI手册(部份)

    在阅读《Spring ACEGI手册(部分)》.doc文档时,可以深入学习如何配置和使用该框架,以及如何解决常见的安全问题。 **总结** Spring ACEGI作为一个强大的安全框架,为开发者提供了丰富的工具和机制来保护应用程序...

    acegi(Spring Security) 参考手册

    总的来说,《Acegi(Spring Security)参考手册》是学习和理解Spring Security不可或缺的资源,无论你是初学者还是有经验的开发者,都能从中获取到实用的知识和深入的理解,以构建更加安全、健壮的Spring应用。...

Global site tag (gtag.js) - Google Analytics