Spring security 4 之 SSO+Form两种登录方式

前一遍讲的是SSO的简单配置,项目中有时会用到SSO+LoginFrom 两种登录方式的情况,

Spring security同样可以实现,在之前SSO的基础上加入FORM_LOGIN_FILTER过滤器即可

上配置:

<security:http auto-config="false" use-expressions="false" entry-point-ref="ssoAuthenticationEntryPoint">

	<security:custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="metadataSourceFilter"  />

	<security:access-denied-handler error-page="/ssoLogin.jsp"/>

	<security:custom-filter position="PRE_AUTH_FILTER" ref="ssoAuthenticatedFilter" />

	<security:custom-filter position="LOGOUT_FILTER" ref="ssoLogoutFilter" />

	<span style="color:#ff6666;"><security:custom-filter ref="usernamePasswordFilter" position="FORM_LOGIN_FILTER" /></span>

	<security:csrf disabled="true"/>  <!-- token-repository-ref="csrfTokenRepository" request-matcher-ref="csrfRequiresMatcher"-->
	<security:headers>
		<security:frame-options disabled="true" />  <!--policy="SAMEORIGIN"  iframe安全等级-->
	</security:headers>
</security:http>

<!--SSO验证入口-->
<bean id="ssoAuthenticationEntryPoint" class="com.XX.eip.saif.security.SSOAuthenticationEntryPoint">
	<property name="loginUrl" value="/ssoLogin.jsp" /> <!-- //SSO登录地址 -->
</bean>

<!--SSO认证过滤器-->
<bean id="ssoAuthenticatedFilter" class="com.XX.eip.saif.security.SSOAuthenticatedFilter">
	<property name="securityKey" value="Hqsn/qU5iYY=" />
	<property name="securityIV" value="Q9TMVAdPK0k=" />
	<property name="authenticationManager" ref="authenticationManager" />
</bean>

<!--验证管理器 只能定义一个-->
<security:authentication-manager alias="authenticationManager" >       <!--erase-credentials="false" -->
	<!--SSO验证管理器-->
	<security:authentication-provider ref="authenticationProvider"/>
	<!--用户密码验证管理器-->
	<span style="color:#ff0000;"><security:authentication-provider ref="userPasswordAuthenticationProvider"/></span>
</security:authentication-manager>

<!--SSO用户验证器-->
<bean id="authenticationProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
	<property name="preAuthenticatedUserDetailsService" ref="authenticationUserDetailsService"/>
</bean>
<bean id="authenticationUserDetailsService" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
	<property name="userDetailsService" ref="userDetailsServiceImpl"/>
</bean>
<bean id="userDetailsServiceImpl" class="com.XX.platform.security.UserDetailsServiceImpl"/>

<!--sso登出拦截器-->
<bean id="ssoLogoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
	<constructor-arg value="/ssoLogout.jsp"/>
	<constructor-arg>
		<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
	</constructor-arg>
</bean>


<!-- 用户名密码登录拦截器 -->
<bean id="usernamePasswordFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
	<property name="authenticationManager" ref="authenticationManager" />
	<property name="authenticationSuccessHandler">
		<bean class=" com.XX.platform.security.SavedRequestAwareAuthenticationSuccessHandler">
			<property name="defaultTargetUrl" value="/" />
			<property name="alwaysUseDefaultTargetUrl" value="true"/>
		</bean>
	</property>
	<property name="authenticationFailureHandler">
		<bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
			<property name="defaultFailureUrl" value="/login.jsp?error=1" />
		</bean>
	</property>
</bean>

<!--用户密码验证器-->
<bean id="userPasswordAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
	<property name="hideUserNotFoundExceptions" value="false" />
	<property name="userDetailsService" ref="userDetailsServiceImpl" />
	<property name="passwordEncoder" ref="passwordEncoder" />
	<property name="saltSource" ref="saltSource" />
</bean>
<bean id="passwordEncoder" class="com.XX.platform.security.Md5PasswordEncoder" />
<bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource">
	<property name="userPropertyToUse" value="username"/>
</bean>


<!--intercept-url过滤器-->
<bean id="metadataSourceFilter" class="com.XX.platform.security.MetadataSourceSecurityInterceptor">
	<property name="authenticationManager" ref="authenticationManager" />
	<property name="accessDecisionManager" ref="accessDecisionManager" />
	<property name="securityMetadataSource" ref="metadataSource" />
</bean>
<bean id="accessDecisionManager" class="com.XX.platform.security.AccessDecisionManager"/>
<bean id="metadataSource" init-method="loadResourceConfig" class="com.XX.platform.security.MetadataSource"/>


<bean id="csrfTokenRepository" class="org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository" />
<bean id="csrfRequiresMatcher" class="com.XX.platform.security.CsrfRequiresMatcher" />

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
	<property name="basename" value="classpath:config/messages-security" />
</bean>
这里容易遇到的问题是 authentication-manager的配置, 这个不能配置两个,只会有一个生效,

但是里面的子节点authentication-provider却是可以配置多个的, 查看源代码 org.springframework.security.authentication.ProviderManager,

public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        Class toTest = authentication.getClass();
        Object lastException = null;
        Authentication result = null;
        boolean debug = logger.isDebugEnabled();
        Iterator e = this.getProviders().iterator();

        while(e.hasNext()) {
            AuthenticationProvider provider = (AuthenticationProvider)e.next();
            if(provider.supports(toTest)) {
                if(debug) {
                    logger.debug("Authentication attempt using " + provider.getClass().getName());
                }

                try {
                    result = provider.authenticate(authentication);
                    if(result != null) {
                        this.copyDetails(authentication, result);
                        break;
                    }
                } catch (AccountStatusException var11) {
                    this.prepareException(var11, authentication);
                    throw var11;
                } catch (InternalAuthenticationServiceException var12) {
                    this.prepareException(var12, authentication);
                    throw var12;
                } catch (AuthenticationException var13) {
                    lastException = var13;
                }
            }
        }

        。。。。。。。。
    }
从while循环就可以明白原理了, 实际上是循环配置的 authentication-provider, 逐个验证,遇到验证通过的即终止break, 所以集成两个登录方式在这里就可以实现各自的验证了

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值