美文网首页spring-security5.0
spring-security-5.0版本的xml基本配置

spring-security-5.0版本的xml基本配置

作者: Aysn | 来源:发表于2018-01-30 20:46 被阅读0次

    首先先上全部的xml的配置,代码如下

    <?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.xsd
                 http://www.springframework.org/schema/security
                 http://www.springframework.org/schema/security/spring-security.xsd">
        <beans:description>SpringSecurity安全配置</beans:description>
        <!-- http安全配置 -->
        <http use-expressions="true" auto-config="false"
            entry-point-ref="authenticationEntryPoint" name="empire"
            authentication-manager-ref="authenticationManager">
            <!-- session过滤器 -->
            <custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
            <!-- <intercept-url pattern="/static/**" access="permitAll" /> -->
            <intercept-url pattern="/**/*.jpg" access="permitAll" />
            <intercept-url pattern="/**/*.png" access="permitAll" />
            <intercept-url pattern="/**/*.gif" access="permitAll" />
            <intercept-url pattern="/**/*.css" access="permitAll" />
            <intercept-url pattern="/**/*.js" access="permitAll" />
            <!-- 尝试访问没有权限的页面时跳转的页面 -->
            <access-denied-handler error-page="/static/403.html" />
            <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR" />
            <!-- ajax登录过滤器 -->
            <!-- <custom-filter before="FORM_LOGIN_FILTER" ref="ajaxLoginFilter" /> -->
            <custom-filter position="FORM_LOGIN_FILTER" ref="adminAjaxLoginFilter" />
            <!-- <custom-filter after="FORM_LOGIN_FILTER" ref="loginFilter" /> -->
            <headers>
                <frame-options policy="SAMEORIGIN"></frame-options>
            </headers>
            <!-- 只cache get,避免ajax post 被cache -->
            <request-cache ref="httpSessionRequestCache" />
            <session-management
                session-authentication-strategy-ref="sessionAuthenticationStrategy" />
            <!-- 注销过滤器 -->
            <!-- <logout invalidate-session="true" logout-success-url="/admin/login.html?logout=true" 
                logout-url="/j_spring_security_logout" /> -->
            <!-- 启用安全策略 -->
            <csrf disabled="false" token-repository-ref="csrfTokenRepository"
                request-matcher-ref="csrfSecurityRequestMatcher" />
            <custom-filter ref="rememberMeFilter" position="REMEMBER_ME_FILTER" />
            <custom-filter ref="logoutFilter" position="LOGOUT_FILTER" />
            <access-denied-handler ref="accessDeniedHandler" />
        </http>
        <beans:bean id="csrfSecurityRequestMatcher"
            class="pn.empire.security.handler.CsrfSecurityRequestMatcher">
            <beans:property name="execludeUrls">
                <beans:list>
                    <beans:value>/workorder/adminuploadattachment.html</beans:value>
                    <beans:value>/face/</beans:value>
                </beans:list>
            </beans:property>
        </beans:bean>
        <!-- -->
        <beans:bean id="accessDeniedHandler"
            class="pn.empire.security.handler.AccessDeniedHandlerImpl">
            <beans:property name="errorPage" value="/static/405.html"></beans:property>
        </beans:bean>
        <!--remember-me拦截器 -->
        <beans:bean id="rememberMeFilter"
            class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
            <beans:constructor-arg ref="authenticationManager" />
            <beans:constructor-arg ref="rememberMeServices" />
        </beans:bean>
        <beans:bean id="rememberMeServices"
            class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
            <beans:constructor-arg value="key" />
            <beans:constructor-arg ref="userDetailsService" />
            <beans:constructor-arg ref="tokenRepository" />
            <beans:property name="tokenValiditySeconds" value="604800" />
        </beans:bean>
    
        <beans:bean id="tokenRepository"
            class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl">
            <beans:property name="dataSource" ref="dataSourceMysql" />
            <!-- <beans:property name="createTableOnStartup" value="true"/> --> <!-- 是否在系统启动时创建持久化token的数据库表 -->
        </beans:bean>
    
        <beans:bean id="rememberMeAuthenticationProvider"
            class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
            <beans:constructor-arg value="key" />
        </beans:bean>
        <!--remember-me拦截器 end -->
        <!--登出拦截器 -->
        <beans:bean id="logoutFilter"
            class="org.springframework.security.web.authentication.logout.LogoutFilter">
            <beans:constructor-arg value="/admin/unlogin.html?logout=true" />
            <beans:property name="filterProcessesUrl" value="/j_spring_security_logout" />
            <beans:constructor-arg>
                <beans:list>
                    <beans:ref bean="rememberMeServices" />
                    <beans:bean
                        class="org.springframework.security.web.csrf.CsrfLogoutHandler">
                        <beans:constructor-arg ref="csrfTokenRepository" />
                    </beans:bean>
                    <beans:bean
                        class="org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler">
                        <beans:constructor-arg index="0">
                            <beans:array>
                                <beans:value>JSESSIONID</beans:value>
                                <beans:value>remember-me</beans:value>
                            </beans:array>
                        </beans:constructor-arg>
                    </beans:bean>
                    <beans:bean
                        class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
                </beans:list>
            </beans:constructor-arg>
        </beans:bean>
        <beans:bean id="csrfTokenRepository"
            class="org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository" />
    
    
    
        <!-- session 控制 -->
        <beans:bean id="concurrencyFilter"
            class="pn.empire.security.filter.ConcurrentSessionFilter">
            <beans:constructor-arg ref="sessionRegistry" />
            <beans:constructor-arg value="/static/406.html" />
        </beans:bean>
        <beans:bean id="sessionAuthenticationStrategy"
            class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
            <beans:constructor-arg>
                <beans:list>
                    <beans:bean
                        class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
                        <beans:constructor-arg ref="sessionRegistry" />
                        <beans:property name="maximumSessions" value="1" />
                        <beans:property name="exceptionIfMaximumExceeded"
                            value="false" />
                    </beans:bean>
                    <beans:bean
                        class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy" />
                    <beans:bean
                        class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
                        <beans:constructor-arg ref="sessionRegistry" />
                    </beans:bean>
                </beans:list>
            </beans:constructor-arg>
        </beans:bean>
        <beans:bean id="sessionRegistry"
            class="org.springframework.security.core.session.SessionRegistryImpl" />
        <!-- session 控制 end -->
        <!-- 一个自定义的filter,必须包含authenticationManager,accessDecisionManager,securityMetadataSource三个属性, 
            我们的所有控制将在这三个类中实现,解释详见具体配置 -->
        <beans:bean id="myFilter"
            class="pn.empire.security.filter.SecurityInterceptorFilter">
            <beans:property name="authenticationManager" ref="authenticationManager" />
            <beans:property name="accessDecisionManager" ref="accessDecisionManager" />
            <beans:property name="securityMetadataSource" ref="securityMetadataSource" />
        </beans:bean>
        <beans:bean id="authSuccess"
            class="pn.empire.security.handler.AuthenticationSuccessHandler" />
        <beans:bean id="logoutSuccessHandler"
            class="pn.empire.security.handler.LogoutSuccessHandler" />
        <!-- 验证配置 , 认证管理器,实现用户认证的入口,主要实现UserDetailsService接口即可 -->
        <authentication-manager alias="authenticationManager"
            erase-credentials="false">
            <authentication-provider user-service-ref="userDetailsService">
                <!-- 登入 密码 采用MD5加密 -->
                <password-encoder ref="passwordEncoder"/>
            </authentication-provider>
            <authentication-provider ref="rememberMeAuthenticationProvider" />
        </authentication-manager>
        <beans:bean id="passwordEncoder" class="pn.empire.security.handler.PwdEncodeHandler" />
        <!-- 项目实现的用户查询服务,将用户信息查询出来 -->
        <beans:bean id="userDetailsService"
            class="pn.empire.security.service.impl.UserDetailServiceImpl" />
        <!-- 访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 -->
        <beans:bean id="accessDecisionManager"
            class="pn.empire.security.service.impl.AccessDecisionManager" />
        <!-- 资源源数据定义,将所有的资源和权限对应关系建立起来,即定义某一资源可以被哪些角色访问 -->
        <beans:bean id="securityMetadataSource"
            class="pn.empire.security.service.impl.InvocationSecurityMetadataSource" />
    
        <beans:bean id="messageSource"
            class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
            <beans:property name="basename"
                value="classpath:org/springframework/security/messages_zh_CN" />
        </beans:bean>
        <beans:bean id="authenticationEntryPoint"
            class="pn.empire.security.service.impl.AuthenticationEntryPoint">
            <beans:constructor-arg name="loginFormUrl"
                value="/admin/unlogin.html?entrypoint" />
        </beans:bean>
        <!-- 验证ajax请求 -->
        <beans:bean id="ajaxLoginFilter"
            class="pn.empire.security.filter.UsernamePasswordFilter">
            <beans:property name="authenticationManager" ref="authenticationManager" />
            <beans:property name="authenticationFailureHandler"
                ref="ajaxFailureHandler" />
            <beans:property name="authenticationSuccessHandler"
                ref="ajaxSuccessHandler" />
            <beans:property name="filterProcessesUrl" value="/ajaxLoginProcess" />
            <beans:property name="sessionAuthenticationStrategy"
                ref="sessionAuthenticationStrategy" />
        </beans:bean>
        <beans:bean id="ajaxFailureHandler"
            class="pn.empire.security.handler.AjaxAuthenticationFailureHandler">
        </beans:bean>
        <beans:bean id="ajaxSuccessHandler"
            class="pn.empire.security.handler.AjaxAuthenticationSuccessHandler">
        </beans:bean>
        <!-- 验证admin ajax请求 -->
        <beans:bean id="adminAjaxLoginFilter"
            class="pn.empire.security.filter.UsernamePasswordFilter">
            <beans:property name="authenticationManager" ref="authenticationManager" />
            <beans:property name="authenticationFailureHandler"
                ref="adminAjaxFailureHandler" />
            <beans:property name="authenticationSuccessHandler"
                ref="adminAjaxSuccessHandler" />
            <beans:property name="filterProcessesUrl" value="/adminAjaxLoginProcess" />
            <beans:property name="sessionAuthenticationStrategy"
                ref="sessionAuthenticationStrategy" />
            <beans:property name="rememberMeServices" ref="rememberMeServices" />
        </beans:bean>
        <beans:bean id="adminAjaxFailureHandler"
            class="pn.empire.security.handler.AdminAjaxAuthenticationFailureHandler">
        </beans:bean>
        <beans:bean id="adminAjaxSuccessHandler"
            class="pn.empire.security.handler.AdminAjaxAuthenticationSuccessHandler">
        </beans:bean>
        <!-- 验证普通用户 -->
        <beans:bean id="loginFilter"
            class="pn.empire.security.filter.UsernamePasswordFilter">
            <beans:property name="authenticationManager" ref="authenticationManager" />
            <beans:property name="authenticationFailureHandler"
                ref="failureHandler" />
            <beans:property name="authenticationSuccessHandler"
                ref="authSuccess" /> <!-- ref="successHandler"/> -->
            <beans:property name="filterProcessesUrl" value="/loginProcess" />
            <beans:property name="sessionAuthenticationStrategy"
                ref="sessionAuthenticationStrategy" />
        </beans:bean>
    
        <beans:bean id="failureHandler"
            class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
            <beans:property name="defaultFailureUrl" value="/admin/login.html?login_error=1" />
        </beans:bean>
    
        <beans:bean id="successHandler"
            class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
            <beans:property name="alwaysUseDefaultTargetUrl" value="false" />
            <beans:property name="defaultTargetUrl" value="/" />
        </beans:bean>
        <beans:bean id="httpSessionRequestCache"
            class="org.springframework.security.web.savedrequest.HttpSessionRequestCache">
        </beans:bean>
    </beans:beans>
    

    首先来说http配置:
    1.use-expressions:是否启用intercept-url元素的access属性对Spring EL表达式的支持,但是在配置中并没有使用到。
    2.auto-config:是否启用默认配置,在配置中设置为false,基本都采用自定义配置。

    1. entry-point-ref:第三方登录入口,认证不通过则抛出一个异常给ExceptionTranslationFilter,由它进行通过entry-point-ref设置的入口点进行处理,通过此配置可以重定向到其他页面。
      4.authentication-manager-ref:引用的AuthenticationManager,指定身份验证bean,我觉得可以算作核心了。
      5.session过滤器,代码如下:
      <custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
    

    主要功能为当用户session过期用户却继续访问时,系统会跳转至指定路径。
    6.access-denied-handler:访问失败才会进AccessDeniedHandler,如果是未登录或者会话超时等,不会触发AccessDeniedHandler,而是会直接跳转到登录页面
    7.custom-filter:自定义登录登出记住我过滤器。
    8.开启csrf,csrf生成的token是存储在cookies中,防止跨域攻击,所以并不能防止重复提交。
    9.为了页面中可以使用iframe,配置header:

    <headers>
                <frame-options policy="SAMEORIGIN"></frame-options>
    </headers>
    

    下面说一下注册的bean
    1.csrfSecurityRequestMatcher:这个bean控制了那些路径不需要csrf限制,比如说一些接口、富文本编辑之类。

        private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
        private RegexRequestMatcher unprotectedMatcher = new RegexRequestMatcher("/unprotected", null);
        @Override
        public boolean matches(HttpServletRequest request) {
            if (execludeUrls != null && execludeUrls.size() > 0) {
                String servletPath = request.getServletPath();
                for (String url : execludeUrls) {
                    if (servletPath.contains(url)) {
                        return false;
                    }
                }
            }
            if (allowedMethods.matcher(request.getMethod()).matches()) {
                return false;
            }
            return !unprotectedMatcher.matches(request);
        }
    

    可以看一下代码,除了指定路径外,还对GET、HEAD、TRACE、OPTIONS免除了csrf过滤,主要是针对post请求进行过滤。

    2.accessDeniedHandler:访问失败才会进AccessDeniedHandler,如果是未登录或者会话超时等,不会触发AccessDeniedHandler,而是会直接跳转到登录页面。
    3.rememberMeFilter:配置的记住我过滤器,注入身份验证bean以及rememberMeServices。
    4.rememberMeServices:注入userDetailsService和token存储。
    5.tokenRepository:token处理方式,在配置中选择在数据库中进行存储
    6.rememberMeAuthenticationProvider:token的处理类,key要一致,官方说明如下:

    This implementation supports the simpler approach described in [Section 18.2, “Simple Hash-Based Token Approach”](https://docs.spring.io/spring-security/site/docs/5.0.0.RELEASE/reference/htmlsingle/#remember-me-hash-token "18.2 Simple Hash-Based Token Approach"). `TokenBasedRememberMeServices` generates a `RememberMeAuthenticationToken`, which is processed by `RememberMeAuthenticationProvider`. A `key` is shared between this authentication provider and the `TokenBasedRememberMeServices`. In addition, `TokenBasedRememberMeServices` requires A UserDetailsService from which it can retrieve the username and password for signature comparison purposes, and generate the `RememberMeAuthenticationToken` to contain the correct `GrantedAuthority` s. Some sort of logout command should be provided by the application that invalidates the cookie if the user requests this. `TokenBasedRememberMeServices` also implements Spring Security’s `LogoutHandler` interface so can be used with `LogoutFilter` to have the cookie cleared automatically.
    
    The beans required in an application context to enable remember-me services are as follows:
    
    <pre class="programlisting" style="line-height: 1.4; color: black; font-size: 15px; padding: 6px 10px; background-color: rgb(248, 248, 248); border: 1px solid rgb(204, 204, 204); border-radius: 3px; clear: both; overflow: auto; font-family: Consolas, &quot;Liberation Mono&quot;, Courier, monospace; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><bean id="rememberMeFilter" class=
    "org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
    <property name="rememberMeServices" ref="rememberMeServices"/>
    <property name="authenticationManager" ref="theAuthenticationManager" />
    </bean>
    
    <bean id="rememberMeServices" class=
    "org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
    <property name="userDetailsService" ref="myUserDetailsService"/>
    <property name="key" value="springRocks"/>
    </bean>
    
    <bean id="rememberMeAuthenticationProvider" class=
    "org.springframework.security.authentication.RememberMeAuthenticationProvider">
    <property name="key" value="springRocks"/>
    </bean></pre>
    
    Don’t forget to add your `RememberMeServices` implementation to your `UsernamePasswordAuthenticationFilter.setRememberMeServices()` property, include the `RememberMeAuthenticationProvider` in your `AuthenticationManager.setProviders()` list, and add `RememberMeAuthenticationFilter` into your `FilterChainProxy` (typically immediately after your `UsernamePasswordAuthenticationFilter`).
    
    

    7.logoutFilter:自定义登出过滤器,之所以配置这么复杂是为了配合remember-me功能、以及用户只能在一处登录的功能、csrf过滤用能使用。
    8.csrfTokenRepository:csrfToken仓库,用户访问后会生成csrf token存在用户浏览器的cookies中,会对用户每次符合验证规则的请求进行token校验,防止跨域攻击,但是不能防止重复提交。在一个会话中,token是一致的。
    9.myFilter:继承AbstractSecurityInterceptor,负责处理HTTP资源的安全性。整个过程需要依赖AuthenticationManager、AccessDecisionManager和FilterInvocationSecurityMetadataSource。
    10.authSuccess:自定义的表单登录成功处理器。
    11.logoutSuccessHandler:登出成功处理器
    12.authenticationManager:用户信息认证管理器。
    13.passwordEncoder:根据自定义加密方式进行比对
    14.userDetailsService:自定义用户信息类。
    15.accessDecisionManager:访问决策器,定义了资源可以被哪些角色访问。
    16.securityMetadataSource:资源-角色对应关系。
    17.messageSource:security的国际化加载
    18.authenticationEntryPoint:第三方登录入口,自定义该bean主要是为了ajax登录。
    19.ajaxLoginFilter:ajax登录过滤器。
    20.ajaxFailureHandler:ajax登录失败处理器
    21.ajaxSuccessHandler:ajax登录成功处理器
    下面就类似了,当初定义了三个登录不同的界面,所以写才的如此麻烦。
    httpSessionRequestCache:可以理解为缓存控制。

    个人觉得spring-security的精髓在于自定义,可以通过自定义来满足几乎所有的业务需求。
    在之后的文章中会详细说明各个自定义bean。
    以上个人拙见,欢迎大家指教。

    相关文章

      网友评论

        本文标题:spring-security-5.0版本的xml基本配置

        本文链接:https://www.haomeiwen.com/subject/tjfknxtx.html