[置顶] Spring Security定制开发 单点登录CAS定制开发 集成 配置文件

package com.gwtjs.sso.server;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jasig.cas.authentication.principal.Credentials;
import org.jasig.cas.authentication.principal.CredentialsToPrincipalResolver;
import org.jasig.cas.authentication.principal.Principal;
import org.jasig.cas.authentication.principal.SimplePrincipal;
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
import org.springframework.jdbc.core.JdbcTemplate;
/**
 * 
 * <h2>传送更多用户信息</h2>
 * <p>
 * 如果是默认配置,只能传输用户名到客户端,现希望可以传送更多的信息给客户端,例如,用户拥有的权限信息,可以传给客户
 * </p>
 * <pre>
 * 参考: * </pre>
 * @author gwtjs.com
 * 
 */
public class BaseCredentialsToPrincipalResolver implements
		CredentialsToPrincipalResolver {

	//private static final Logger logger = Log4jLoggerFactory.getLogger(BaseCredentialsToPrincipalResolver.class);

	private JdbcTemplate jdbcTemplate;

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	public Principal resolvePrincipal(Credentials credentials) {
		UsernamePasswordCredentials up = (UsernamePasswordCredentials) credentials;

		// 获取登录帐户
		//logger.debug("登录用户:" + up.getUsername());
		// System.out.println(up.getPassword());

		final Map<String, Object> attr = new HashMap<String, Object>();
		// ,USER_NAME,ENABLED,ISSYS
		String sql = "SELECT USER_ACCOUNT username from SYS_USERS where ENABLED = 1 and USER_ACCOUNT ='"
				+ up.getUsername() + "'";

		List<String> list = jdbcTemplate.queryForList(sql, String.class);
		attr.put(up.getUsername(), list);

		Principal p = new SimplePrincipal(up.getUsername(), attr);
		return p;
	}

	public boolean supports(Credentials credentials) {
		return credentials != null
				&& UsernamePasswordCredentials.class
						.isAssignableFrom(credentials.getClass());
	}

}


 

package com.gwtjs.sso.server;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Set;
import java.util.HashSet;

import org.jasig.cas.authentication.handler.AuthenticationException;
import org.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.authentication.dao.SaltSource;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.core.GrantedAuthority;

import com.gwtjs.sso.server.model.BaseUser;
import com.gwtjs.sso.server.model.BaseUserDetail;

/**
 * 登陆时使用的工具
 */
public class UsernamePasswordJDBCAuthenticationHandler extends
		AbstractUsernamePasswordAuthenticationHandler {

	private JdbcTemplate jdbcTemplate;

	private PasswordEncoder passEncoder;

	private SaltSource saltSource;

	/**
	 * 登陆时使用的方法
	 */
	protected boolean authenticateUsernamePasswordInternal(
			UsernamePasswordCredentials credentials)
			throws AuthenticationException {
		final String username = credentials.getUsername();
		final String password = credentials.getPassword();
		System.out.println("username:" + username + "  --> password:"
				+ password);
		String sql = "select USER_ID,USER_ACCOUNT,USER_NAME,USER_PASSWORD from SYS_USERS where ENABLED = 1 and USER_ACCOUNT ='"
				+ username + "'";
		BaseUser baseUser = jdbcTemplate.queryForObject(sql, null,
				new RowMapper<baseuser>() {
					@Override
					public BaseUser mapRow(ResultSet rs, int rowNum)
							throws SQLException {
						BaseUser baseuser = new BaseUser();
						baseuser.setCode(rs.getString("USER_ID"));
						baseuser.setUserAccount(rs.getString("USER_ACCOUNT"));
						baseuser.setUserPassword(rs.getString("USER_PASSWORD"));
						baseuser.setUserName(rs.getString("USER_NAME"));
						return baseuser;
					}

				});

		Set<grantedauthority> auth = new HashSet<grantedauthority>();
		GrantedAuthority ga = (GrantedAuthority) new SimpleGrantedAuthority("admin");
		auth.add(ga);
		
		/*
		 BaseUserDetail(String userAccount, String username, String userPassword, String code, boolean enabled, boolean issys, boolean accountNonExpired, boolean accountNonLocked, Set<grantedauthority> auth)
		 */
		BaseUserDetail user = new BaseUserDetail(username,
				baseUser.getUserName(), baseUser.getUserPassword(),
				baseUser.getCode(), true, true, true, true, auth);
		System.out.println(user);
		if (user != null) {
			//System.out.println("saltSource.getSalt(user) ...  "+ saltSource.getSalt(user));
			// 验证密码
			/*String encodePassword = this.passEncoder.encodePassword(password,
					this.saltSource.getSalt(user));*/
			String encodePassword = this.passEncoder.encodePassword(password, user.getUserAccount());
			System.out.println("password ...  " + password);
			System.out.println("UserAccount ...  " + user.getUserAccount());
			System.out.println("username ...  " + username);
			System.out.println("encodePassword ...  " + encodePassword);
			System.out.println("user.getPassword ...  " + user.getPassword());
			if (encodePassword.equals(user.getPassword())) {
				return true;
			}
		}
		return false;
	}

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	public void setPassEncoder(PasswordEncoder passEncoder) {
		this.passEncoder = passEncoder;
	}

	public void setSaltSource(SaltSource saltSource) {
		this.saltSource = saltSource;
	}

}




 MD%加密算法有问题:

String encodePassword = this.passEncoder.encodePassword(user.getUserAccount(), password);

username:dzg  --> password:dzg1
encodePassword ...  042c1c7be2a9a18f96be3b2169d663a6

username:dzg  --> password:dzg1
encodePassword ...  042c1c7be2a9a18f96be3b2169d663a6

String encodePassword = this.passEncoder.encodePassword( password,user.getUserAccount());
username:dzg  --> password:dzg1
encodePassword ...  c2ae6fdc2054ae785d5482d1270904b4
数据库结果:
encodePassword ...  C857A25F749F1FE0A28427AFE853C4F8

username:dzg  --> password:dzg1
BaseUserDetail [
userId=dzg4, userAccount=dzg, username=董正光,
userPassword=C857A25F749F1FE0A28427AFE853C4F8, userDesc=null, enabled=true,
issys=true,
userDept=null, userDuty=null, password=null, authorities=[admin],
accountNonExpired=true, accountNonLocked=true, credentialsNonExpired=false]
password ...  dzg1
UserAccount ...  dzg
username ...  dzg
encodePassword ...  c2ae6fdc2054ae785d5482d1270904b4
user.getPassword ...  null

 

 

cas/web/WEB-INF/deployerConfigContext.xml

完整的配置文件,security使用完全的数据验证,cas使用数据验证;

<?xml version="1.0" encoding="UTF-8"?>
<!-- | deployerConfigContext.xml centralizes into one file some of the declarative 
	configuration that | all CAS deployers will need to modify. | | This file 
	declares some of the Spring-managed JavaBeans that make up a CAS deployment. 
	| The beans declared in this file are instantiated at context initialization 
	time by the Spring | ContextLoaderListener declared in web.xml. It finds 
	this file because this | file is among those declared in the context parameter 
	"contextConfigLocation". | | By far the most common change you will need 
	to make in this file is to change the last bean | declaration to replace 
	the default SimpleTestUsernamePasswordAuthenticationHandler with | one implementing 
	your approach for authenticating usernames and passwords. + -->
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:sec="http://www.springframework.org/schema/security"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">


	<bean id="authenticationManager" class="org.jasig.cas.authentication.AuthenticationManagerImpl">

		<property name="credentialsToPrincipalResolvers">
			<list>
				<!-- 此处修改了CredentialToPrincipal,因为除了要传递用户信息之处,还要传递一部分权限信息 若无此需求,可使用UsernamePasswordCredentialsToPrincipalResolver(系统默认) -->
				<bean
					class="com.gwtjs.hacom.vgop.security.cas.BaseUsernamePasswordCredentialsToPrincipalResolver"
					p:jdbcTemplate-ref="jdbcTemplate">
					<property name="attributeRepository" ref="attributeRepository" />
				</bean>
				<bean
					class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver" />
			</list>
		</property>
		<property name="authenticationHandlers">
			<list>

				<bean
					class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
					p:httpClient-ref="httpClient"><!-- p:requireSecure="true" -->
					<property name="requireSecure" value="false" />
				</bean>

				<!-- 使用我们自己的验证方式 -->
				<bean
					class="com.gwtjs.hacom.vgop.security.cas.UsernamePasswordJDBCAuthenticationHandler"
					p:jdbcTemplate-ref="jdbcTemplate" p:passEncoder-ref="passwordEncoder">
					<!-- p:saltSource-ref="saltSource" -->
				</bean>

			</list>
		</property>
	</bean>
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
		<property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl" />
		<property name="username" value="FrameworkTest" />
		<property name="password" value="FrameworkTest" />
	</bean>

	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
	</bean>

	<!-- autowire="byName" -->
	<bean id="passwordEncoder"
		class="org.springframework.security.authentication.encoding.Md5PasswordEncoder">
		<!-- <constructor-arg index="0"> <value>MD5</value> </constructor-arg> -->
	</bean>
	<sec:user-service id="userDetailsService">
		<sec:user name="@@THIS SHOULD BE REPLACED@@" password="notused"
			authorities="ROLE_ADMIN" />
	</sec:user-service><!-- 角色权限更多信息可在此关联,使用SingleRowJdbcPersonAttributeDao 
		获取更多用户的信息 -->
	<bean id="attributeRepository"
		class="org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao">
		<constructor-arg index="0" ref="dataSource" />
		<constructor-arg index="1"
			value="select USER_ID USERID,USER_ACCOUNT ACCOUNT,USER_PASSWORD PASSWORD from sys_users where USER_ACCOUNT = ?" />
		<!--这里的key需写username,value对应数据库用户名字段 -->
		<property name="queryAttributeMapping">
			<map>
				<entry key="username" value="USERID" />
			</map>
		</property>
		<!--key对应数据库字段,value对应客户端获取参数 -->
		<property name="resultAttributeMapping">
			<map>
				<!--这个从数据库中获取的角色,用于在应用中security的权限验证 -> key为对应的数据库字段名称,value为提供给客户端获取的属性名字,系统会自动填充值 -->
				<entry key="UID" value="userId" />
				<entry key="userAccount" value="authorities" />
				<entry key="userAccount" value="username" />
				<entry key="PASSWORD" value="userPassword" />
			</map>
		</property>
	</bean>
	<bean id="serviceRegistryDao" class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl">
	</bean>
	
	<bean id="auditTrailManager"
		class="com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager" />

</beans>







client applicationContext-security.xml

<?xml version="1.0" encoding="UTF-8"?>

<b:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:b="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-3.1.xsd
    http://www.springframework.org/schema/security 
    http://www.springframework.org/schema/security/spring-security-3.0.xsd">


    <!-- entry-point-ref="casEntryPoint"cas切入点 -->
    <http auto-config="true" access-denied-page="/accessDenied.jsp"
        entry-point-ref="casEntryPoint">
        <intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY" />
        <!-- 不要过滤图片等静态资源 -->
        <intercept-url pattern="/**/*.jpg" filters="none" />
        <intercept-url pattern="/**/*.png" filters="none" />
        <intercept-url pattern="/**/*.gif" filters="none" />
        <intercept-url pattern="/**/*.css" filters="none" />
        <intercept-url pattern="/**/*.js" filters="none" />

        <intercept-url pattern="/login.action" filters="none" />
        <intercept-url pattern="/UserTestLoginServlet" filters="none" />

        <intercept-url pattern="/security-flash" />

        <!-- 登录页面和忘记密码页面不过滤 --><!-- 先前的登陆不需要了 -->
        <!-- <intercept-url pattern="/login.jsp" filters="none" /> -->
        <intercept-url pattern="/forgotpassword.jsp" filters="none" />

        <!-- <form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?error=true" 
            default-target-url="/index.jsp" /> -->

        <!-- "记住我"功能,采用持久化策略(将用户的登录信息存放在数据库表中) -->
        <remember-me data-source-ref="dataSource" /><!-- Uncomment 
            to limit the number of sessions a user can have 检测失效的sessionId,超时时定位到另外一个URL -->
        <session-management invalid-session-url="/sessionTimeout.jsp">
            <!-- max-sessions是设置单个用户最大并行会话数; error-if-maximum-exceeded是配置当用户登录数达到最大时是否报错, 
                设置为true时会报错且后登录的会话不能登录 -->
            <concurrency-control max-sessions="3"
                error-if-maximum-exceeded="true" />
        </session-management>

        <!-- webservices验证 -->
        <http-basic />

        <!-- CAS过滤器链放在基础过滤器前面 -->
        <custom-filter position="CAS_FILTER" ref="casFilter" />

        <!-- 增加一个自定义的filter,放在FILTER_SECURITY_INTERCEPTOR之前, 实现用户、角色、权限、资源的数据库管理。 
            11/3/23 -->
        <custom-filter ref="customFilter" before="FILTER_SECURITY_INTERCEPTOR" />
        <!-- 来宾用户名 -->
        <anonymous username="Guest" />

        <!-- <logout logout-success-url="/cas-logout.jsp" /> -->
        <!-- 单点登陆 过滤器 -->
        <custom-filter ref="requestSingleLogoutFilter" before="LOGOUT_FILTER" />
        <!-- 单点登陆退出过滤器 -->
        <custom-filter ref="singleLogoutFilter" before="CAS_FILTER" />

    </http>
    <b:bean id="customFilter"
        class="com.huawei.hacmp.security.CustomFilterSecurityInterceptor">
        <b:property name="authenticationManager" ref="authenticationManager" />
        <b:property name="accessDecisionManager" ref="customAccessDecisionManager" />
        <b:property name="securityMetadataSource" ref="customSecurityMetadataSource" />
    </b:bean>

    <!-- 注意能够为authentication-manager 设置alias别名 --><!-- 启用单点登陆后此认证废弃 -->
    <!-- <authentication-manager alias="authenticationManager"> <authentication-provider 
        user-service-ref="userDetailsManager"> <password-encoder ref="passwordEncoder"> 
        <salt-source user-property="username" /> </password-encoder> </authentication-provider> 
        </authentication-manager> -->

    <!-- 用户详细信息管理:数据源、用户缓存(通过数据库管理用户、角色、权限、资源)。(新版本) 11/3/23 在这个类中,你就可以从数据库中读入用户的密码,角色信息,是否锁定,账号是否过期等 -->
    <b:bean id="userDetailsManager" class="com.huawei.hacmp.security.CustomUserDetailsService">
        <b:property name="sysUsersDao" ref="sysUsersDao" />
    </b:bean><!-- 访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源。11/3/23 -->
    <b:bean id="customAccessDecisionManager"
        class="com.huawei.hacmp.security.CustomAccessDecisionManager">
    </b:bean>

    <!-- 资源源数据定义,将所有的资源和权限对应关系建立起来,即定义某一资源可以被哪些角色去访问。11/3/23 -->
    <b:bean id="customSecurityMetadataSource"
        class="com.huawei.hacmp.security.CustomInvocationSecurityMetadataSourceService">
    </b:bean>

    <!-- =====================单点登陆===================== -->
    <!-- cas中心认证服务入口 -->
    <b:bean id="casEntryPoint"
        class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
        <b:property name="loginUrl" value="https://sso.vgop.huawei.com:8443/login" />
        <b:property name="serviceProperties" ref="serviceProperties" />
    </b:bean><!-- 单点登陆服务属性 -->
    <b:bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
        <!-- cas中心认证服务配置,登录成功后的返回地址 -->
        <b:property name="service"
            value="http://sso.vgop.huawei.com:8181/framework/j_spring_cas_security_check" />
        <!-- 根据需要启用此参数,当url传递renew参数并且为true时,无论用户有无认证cookie都会强制进行验证 -->
        <b:property name="sendRenew" value="false" />
    </b:bean>

    <!-- <b:bean id="casFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter"> 
        <b:property name="authenticationManager" ref="authenticationManager" /> </b:bean> -->

    <!-- CAS service ticket(中心认证服务凭据)验证 -->
    <b:bean id="casFilter"
        class="org.springframework.security.cas.web.CasAuthenticationFilter">
        <b:property name="authenticationManager" ref="authenticationManager" />
        <!-- <b:property name="authenticationSuccessHandler" ref="authenticationSuccessHandler" 
            /> <b:property name="authenticationFailureHandler" ref="authenticationFailureHandler" 
            /> -->
    </b:bean>
    <authentication-manager alias="authenticationManager">
        <authentication-provider ref="casAuthenticationProvider" />
    </authentication-manager>

    <b:bean id="casAuthenticationProvider"
        class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
        <b:property name="authenticationUserDetailsService">
            <b:bean
                class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
                <b:constructor-arg ref="userDetailsManager" />
            </b:bean>
        </b:property>
        <b:property name="serviceProperties" ref="serviceProperties" />
        <b:property name="ticketValidator">
            <b:bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
                <b:constructor-arg index="0"
                    value="https://sso.vgop.huawei.com:8443/" />
            </b:bean>
        </b:property>
        <b:property name="key" value="authorities" />
    </b:bean>
    <b:bean id="casAuthenticationUserDetailsService"
        class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
        <b:property name="userDetailsService" ref="userDetailsManager" />
    </b:bean>

    <b:bean id="requestSingleLogoutFilter"
        class="org.springframework.security.web.authentication.logout.LogoutFilter">
        <b:constructor-arg value="https://sso.vgop.huawei.com:8443/logout" />
        <b:constructor-arg>
            <b:bean
                class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
        </b:constructor-arg>
        <b:property name="filterProcessesUrl" value="/j_spring_cas_security_logout" />
    </b:bean>

    <b:bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter" />

</b:beans>


web.xml

<!-- 用于单点退出,该过滤器用于实现单点登出功能,可选配置-->
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
 
<!-- 该过滤器用于实现单点登出功能,可选配置。 -->
<filter>
    <filter-name>CAS Single Sign Out Filter</filter-name>
    <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CAS Single Sign Out Filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
 
<!-- 该过滤器负责用户的认证工作,必须启用它 -->
<filter>
    <filter-name>CASFilter</filter-name>
    <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
    <init-param>
        <param-name>casServerLoginUrl</param-name>
        <param-value>https://sso.gwtjs.com:8443/cas/login</param-value>
    </init-param>
    <init-param>
        <!--这里的server是服务端的IP-->
        <param-name>serverName</param-name>
        <param-value>http://localhost:10000</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CASFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
 
<!-- 该过滤器负责对Ticket的校验工作,必须启用它 -->
<filter>
    <filter-name>CAS Validation Filter</filter-name>
    <filter-class>
org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
    <init-param>
        <param-name>casServerUrlPrefix</param-name>
        <param-value>https://sso.gwtjs.com:8443/cas</param-value>
    </init-param>
    <init-param>
        <param-name>serverName</param-name>
        <param-value>http://localhost:10000</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CAS Validation Filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
 
<!--
该过滤器负责实现HttpServletRequest请求的包裹,
比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。
-->
<filter>
    <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
    <filter-class>
org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
 
<!--
该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。
比如AssertionHolder.getAssertion().getPrincipal().getName()。
-->
<filter>
    <filter-name>CAS Assertion Thread Local Filter</filter-name>
    <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CAS Assertion Thread Local Filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
 
<!-- 自动根据单点登录的结果设置本系统的用户信息 -->
<filter>
    <display-name>AutoSetUserAdapterFilter</display-name>
    <filter-name>AutoSetUserAdapterFilter</filter-name>
    <filter-class>com.gwtjs.demo.filter.AutoSetUserAdapterFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>AutoSetUserAdapterFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- ======================== 单点登录结束 ======================== -->






你可能感兴趣的:([置顶] Spring Security定制开发 单点登录CAS定制开发 集成 配置文件)