• spring security源码debug [0]


    spring security的典型用法

    配置

    下面是spring-security.xml的配置

    <beans>
    <http pattern="/js/**" security="none"/>
    <http pattern="/logout.jsp" security="none"/>
    <http auto-config="true" use-expressions="true"
        authentication-manager-ref="authenticationManager">
        <headers>
                <frame-options policy="SAMEORIGIN" />
        </headers>
        <csrf disabled="true" />
        <form-login login-page="/login.jsp"
                authentication-failure-url="/login.jsp?error=1"
                always-use-default-target="true"
                default-target-url="/"
                login-processing-url="/j_spring_security_check"
                authentication-success-handler-ref="simpleAuthenticationSuccessHandler"/>
        <logout logout-url="/j_acegi_logout" logout-success-url="/logout.jsp" delete-cookies="JSESSIONID"/>
        <intercept-url pattern="/**" access="isAuthenticated()" />
        <access-denied-handler error-page="/deny.jsp" />
    </http>
    
    
    <authentication-manager alias="authenticationManager">
            <authentication-provider ref="simpleAuthenticationProvider" />
    </authentication-manager>
    </beans>
    

    在web.xml中添加spring的DelegatingFilterProxy

            <!-- Enables Spring Security
            -->
            <filter>
                    <filter-name>springSecurityFilterChain</filter-name>
                    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
                    <init-param>
                            <param-name>contextAttribute</param-name>
                            <param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.controlplane</param-value>
                    </init-param>
            </filter>
            <filter-mapping>
                    <filter-name>springSecurityFilterChain</filter-name>
                    <url-pattern>/*</url-pattern>
            </filter-mapping>
    
    

    其中contextAttribute配置的spring的webapplicationcontext的key name,注意org.springframework.web.servlet.FrameworkServlet.CONTEXT.controlplane最后一个单词controlplane是当前webapp的context的name。

    效果

    简单描述一下以上配置的效果,理解后可以举一反三。每一个都对应一个bean,类型就是DelegatingFilterChain,他们与web.xml中的其他filter同一个层次。当请求一个url时,按注册的顺序匹配各个DelegatingFilterChain匹配的url,如果匹配,那么当前bean根据自己的配置组织一串filter,叫additionalFilter。如security="none"则不用过滤,继续调用web.xml中定义的其他filter。

    对于上文配置中最后一个,挑选一些重要的点,

    • 属性authentication-manager-ref,指定用来做authentication的bean,bean会继续委托providers来做authentication。
    • 子标签. SAMEORIGIN表示该url只能被同源的页面的iframe引用
    • 其他待定。。

    背后的原理是什么

    authentication的过程是什么

    假设用户请求一个需要authentication的url,经过一系列的filter,如图:

    其中UsernamePasswordAuthenticationFilter,是用户名密码方式authentication,如果url不匹配,则跳过当前filter,否则尝试鉴权,从request中准备好username和password,如果sessionId存在也一起放到token中。调用AuthencationManager进行授权。以ProviderAuthenticationManager为例,遍历所有Provider,判断Provider是否支持当前token类型,如果支持那么使用provider鉴权,可能返回鉴权后的token,null或者抛异常。如果失败还委托给parent AuthenticationManager。调用层次就是UsernamePasswordAuthenticationFilter => AuthencationManager => Provider
    如果鉴权成功,调用SessionAuthencationStrategy.onAuthenction,实际就是处理Session,如果不存在就创建,存在则更新。??后续呢
    如果鉴权失败,那么就filter返回,不再继续后续filter,本例中UsernamePasswordAuthencationFilter只过滤/j_spring_securty_check这个url。如果请求该url,就是单纯为了鉴权,并不是为了其他的资源。
    大多数资源都因为不匹配url,而跳过UsernamePasswordAuthencationFIlter。

    DefautltLoginPageGeneratingFilter,定义了loginPageUrl,failureUrl,logoutSuccessUrl,如果匹配,那么生成一个页面作为response返回客户端。否则继续下一个filter。

    BasicAuthenticationFilter,只过滤Header中指定Authorization是Basic的request。如果该username还没有鉴权,则尝试AuthenticationManager鉴权,authentication-manager-ref注册的bean会作为BasicAuthenticationFilter使用AuthenticationManager的parent被使用。如果成功,把token保存到securitycontext(LocalThread的),springsecurtiycontext在后续的sessionmanagerfilter最终会被保存到session对象中。如果鉴权失败则根据配置决定继续filter或者返回失败页面。如果鉴权成功继续filter,此时得到的成果只是把AuthenticationToken对象保存到了SpringSecurityContext对象。

    下一个RequestCacheAwareFilter,待定。用cached request替换request传递到下一个filter

    SecurityContextHolderAwareFilter。wrap request,传递到下一个filter

    AnonymousAuthenticationFilter。如果SpringSecurityContext中没有Authentication,那么创建一个anonymousAuthentication并set到SpringSecurityContext,主要是为了避免null,使得后续处理保持一致。

    SessionManagementFilter。如果当前req的session不存在对应的context,(未提供sessionid或者tomcat的ManagerBase中不能找到sessionid指定的session对象),那么就保存到session,如果session不存在,那么就创建一个session对象,保存到SPRING_SECURITY_CONTEXT。???一直来新的匿名请求不就一直有session吗?哦,没事web.xml中配置了timeout时间。

    ExceptionTranslationFilter。先继续下一个filter,如果捕获到AuthenticationException就cache request和response,呼应之前的RequestCacheAwareFilter,使用定义好的AuthenticationEntryPoint处理当前request。如果AccessDeniedException那么调用对应的accessDeniedHandler。

    FilterSecurityInterceptor。根据配置的,如果url需要拦截调用,获取Authentication对象,使用AccessDecisionManager决定是否通过。策略可以是一票通过,一票否决,多数票通过三种策略。Authentication中包含丰富的user信息,可以灵活decide,主要是role层次的授权,业务相关的授权不适合在这里完成。在中通过SPEL表达式配置进行决策投票。如果授权决策通过,那么继续filter,否则抛出异常AccessDeniedException。在执行filter和service结束后,还会调用AfterInvocationManager,更多是关注response的结果进行拦截,比较少用。

    Tomcat的session

    纵观整个过程,默认tomcat不会为每一个request创建session,而是由webapp自行决定,spring-security是在Authentication成功之后保存SpringSecurityContext的时候,创建session对象。并且如果是AnonymousAuthentication在SessionManagementFilter中也不会saveSpringSecurityContext到session,所以也不会为之创建session对象。

    tomcat的Session对象存储有StandardManager和PersistentManager,前者是内存保存,后者还提供文件保存和jdbc保存。在request.getSession的时候可以选择不存在session时是否创建。

    request的整个经历

    多个filter的完成。
    filter(web.xml)=> DelegatingFilterProxy => filter(web.xml)=> service
    filter(web.xml)<= DelegatingFilterProxy <= filter(web.xml)<= service
    这是一个调用的过程,是嵌套的,而不是链式地一个完成之后就丢掉不再回头。

  • 相关阅读:
    JVM的即时编译器JIT之简单介绍
    JS脚本动态给标签控件添加事件
    getParameterMap的使用
    IOS开发中判断文件是否存在,不存在则拷贝
    javaweb中解决Cookie中文乱码问题
    网页中的上标和下标实现
    Java中枚举的使用
    ASP.NET 首页性能的4大做法
    httpHandlers和httpModules接口介绍 (5)
    css+div排版如何支持所有浏览器
  • 原文地址:https://www.cnblogs.com/linlei2099/p/11993338.html
Copyright © 2020-2023  润新知