CAS 单点登录4.24版本 登录调用其它系统并且返回客户端用其它的用户信息改造

1.登录调用其它系统。修改deployerConfigContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:sec="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <!-- 引入配置文件 -->
<!--     <bean id="propertyConfigurer" -->
<!--           class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> -->
<!--         <property name="location" value="classpath:redis.properties" /> -->
<!--     </bean> -->
    
    <util:map id="authenticationHandlersResolvers">
        <entry key-ref="proxyAuthenticationHandler" value-ref="proxyPrincipalResolver" />
        <entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" />
    </util:map>

    <util:list id="authenticationMetadataPopulators">
        <ref bean="successfulHandlerMetaDataPopulator" />
        <ref bean="rememberMeAuthenticationMetaDataPopulator" />
    </util:list>


    <!-- <alias name="acceptUsersAuthenticationHandler" alias="primaryAuthenticationHandler" /> -->
    
    <!--begin 从数据库中的用户表中读取 -->
    <bean   id="callIntefaceAuthenticationHandler"   name="primaryAuthenticationHandler"    class="com.hivecas.adaptors.CallIntefaceAuthenticationHandler">  
    </bean>
      
     <alias name="userInfoPrincipalResolver" alias="primaryPrincipalResolver" />
     
<!--     <alias name="personDirectoryPrincipalResolver" alias="primaryPrincipalResolver" /> -->
    
    <bean id="attributeRepository" class="org.jasig.services.persondir.support.NamedStubPersonAttributeDao"
          p:backingMap-ref="attrRepoBackingMap" />
          
    <util:map id="attrRepoBackingMap">
        <entry key="uid" value="uid" />
        <entry key="eduPersonAffiliation" value="eduPersonAffiliation" />
        <entry key="groupMembership" value="groupMembership" />
        <entry>
            <key><value>memberOf</value></key>
            <list>
                <value>faculty</value>
                <value>staff</value>
                <value>org</value>
            </list>
        </entry>
    </util:map>
   
    <!--end  从数据库中的用户表中读取 -->
  

    <alias name="serviceThemeResolver" alias="themeResolver" />

    <alias name="jsonServiceRegistryDao" alias="serviceRegistryDao" />

    <!-- <alias name="defaultTicketRegistry" alias="ticketRegistry" /> -->
    <!-- 票据保存方式及有效期设置 -->
	<alias name="redisTicketRegistry" alias="ticketRegistry" />
<!-- 	<bean id="redisTicketRegistry" class="com.hivescm.cas.ticket.registry.RedisTicketRegistry" -->
<!-- 	    p:client-ref="ticketRedisTemplate" -->
<!-- 	    p:tgtTimeout="28800" -->
<!-- 	    p:stTimeout="10"/> -->
	  <bean id="redisTicketRegistry" class="com.hivescm.cas.ticket.registry.RedisClusterTicketRegistry"
	    p:client-ref="redisTemplate"
	    p:tgtTimeout="28800"
	    p:stTimeout="1000"/>
	<!-- redis连接池 -->

<!--     jedis 配置 -->
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig" >
<!--         最大空闲数 -->
        <property name="maxIdle" value="${redis.maxIdle}" />
<!--         最大建立连接等待时间 -->
        <property name="maxWaitMillis" value="${redis.maxWait}" />
<!--         是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个 -->
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean >

<!--     配置文件加载 -->
    <bean id="resourcePropertySource" class="org.springframework.core.io.support.ResourcePropertySource">
        <constructor-arg name="name" value="redis.cluster.properties"/>
        <constructor-arg name="resource" value="classpath:redis.cluster.properties"/>
    </bean>
<!--     redisCluster配置 -->
    <bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration">
        <constructor-arg name="propertySource" ref="resourcePropertySource"/>
    </bean>
<!--     redis服务器中心 -->
    <bean id="connectionFactory"  class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" >
       <constructor-arg name="clusterConfig" ref="redisClusterConfiguration"/>
        <constructor-arg name="poolConfig" ref="poolConfig"/>
        <property name="password" value="${redis.password}" />
        <property name="timeout" value="${redis.timeout}" ></property>
    </bean >
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >
        <property name="connectionFactory" ref="connectionFactory" />
<!--         如果不配置Serializer,那么存储的时候缺省使用String,如果用User类型存储,那么会提示错误User can't cast to String!!  -->
        <property name="keySerializer" >
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
        <property name="valueSerializer" >
            <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
        </property>
        <property name="hashKeySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
        </property>
        <property name="hashValueSerializer">
            <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
        </property>
    </bean >
    
    <alias name="ticketGrantingTicketExpirationPolicy" alias="grantingTicketExpirationPolicy" />
<!--     <alias name="multiTimeUseOrTimeoutExpirationPolicy" alias="serviceTicketExpirationPolicy" /> -->
    <alias name="neverExpiresExpirationPolicy" alias="serviceTicketExpirationPolicy" />

    <alias name="anyAuthenticationPolicy" alias="authenticationPolicy" />
    <alias name="acceptAnyAuthenticationPolicyFactory" alias="authenticationPolicyFactory" />

    <bean id="auditTrailManager"
          class="org.jasig.inspektr.audit.support.Slf4jLoggingAuditTrailManager"
          p:entrySeparator="${cas.audit.singleline.separator:|}"
          p:useSingleLine="${cas.audit.singleline:false}"/>

    <alias name="neverThrottle" alias="authenticationThrottle" />

    <util:list id="monitorsList">
        <ref bean="memoryMonitor" />
        <ref bean="sessionMonitor" />
    </util:list>

    <alias name="defaultPrincipalFactory" alias="principalFactory" />
    <alias name="defaultAuthenticationTransactionManager" alias="authenticationTransactionManager" />
    <alias name="defaultPrincipalElectionStrategy" alias="principalElectionStrategy" />
    <alias name="tgcCipherExecutor" alias="defaultCookieCipherExecutor" />
    
    
</beans>

  2.CallIntefaceAuthenticationHandler

package com.hivecas.adaptors;


import org.apache.commons.lang3.StringUtils;
import org.jasig.cas.authentication.HandlerResult;
import org.jasig.cas.authentication.PreventedException;
import org.jasig.cas.authentication.UsernamePasswordCredential;
import org.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSONObject;
import com.hivecas.model.UsernamePasswordStrongCredential;
import com.hivecas.util.HttpUtil;
import com.hivescm.common.domain.DataResult;
import javax.security.auth.login.AccountNotFoundException;
import javax.security.auth.login.FailedLoginException;
import javax.validation.constraints.NotNull;

import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.Map;

/**
 * 自定义请求接口验证用户登录权限
 * @author lvxt
 *
 */
@Component("callIntefaceAuthenticationHandler")
public class CallIntefaceAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {
	
	@NotNull
    private String requestUrl;
    @Override
    protected final HandlerResult authenticateUsernamePasswordInternal(final UsernamePasswordCredential credential)
            throws GeneralSecurityException, PreventedException {

        if (StringUtils.isBlank(requestUrl)) {
            throw new GeneralSecurityException("Authentication handler is not configured correctly");
        }

        final String username = credential.getUsername();
        final String password = credential.getPassword();
        Map dataMap;
        UsernamePasswordStrongCredential strongCredential;
        try {
        	Map map =new HashMap();
        	map.put("loginName", username);
        	map.put("password", password);
        	String resultJsonStr=HttpUtil.postRequest(requestUrl, map);
        	DataResult data= (DataResult) JSONObject.parseObject(resultJsonStr, DataResult.class);
            if (!data.isSuccess()) {
                throw new FailedLoginException("Password does not match value on record.");
            }
            strongCredential=(UsernamePasswordStrongCredential) credential;
            dataMap=(Map) data.getResult();
            strongCredential.setAttributes(dataMap); 
        } catch (final IncorrectResultSizeDataAccessException e) {
            if (e.getActualSize() == 0) {
                throw new AccountNotFoundException(username + " not found with SQL query");
            } else {
                throw new FailedLoginException("Multiple records found for " + username);
            }
        } catch (final DataAccessException e) {
            throw new PreventedException("SQL exception while executing query for " + username, e);
        }
        return createHandlerResult(strongCredential, this.principalFactory.createPrincipal(username,dataMap), null);
    }
    public String getRequestUrl() {
		return requestUrl;
	}
    @Autowired
	public void setRequestUrl(@Value("${cas.login.auth.request.url:}") String requestUrl) {
		this.requestUrl = requestUrl;
	}
}

  3.UsernamePasswordStrongCredential的改造,用于存入调用登录接口返回的用户信息存入map中

package com.hivecas.model;

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

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.jasig.cas.authentication.UsernamePasswordCredential;

public class UsernamePasswordStrongCredential extends UsernamePasswordCredential  {
	 /** 
     * 带验证码的登录界面 
     */  
    private static final long serialVersionUID = 1L;  
    /** 验证码*/  
    @Size(min = 1, message = "required.authcode")  
    private String authcode;  
    /**登录类型
     * 1.pc登录 2 移动端登录
     */
    @NotNull  
    @Size(min = 1, message = "required.loginType")  
    private String loginType;
    /**
     * 用户返回数据
     */
    private Map<String,Object> attributes = new HashMap<>();
    
  
    public Map<String, Object> getAttributes() {
		return attributes;
	}

	public void setAttributes(Map<String, Object> attributes) {
		this.attributes = attributes;
	}

	public String getLoginType() {
		return loginType;
	}

	public void setLoginType(String loginType) {
		this.loginType = loginType;
	}

	/** 
     *  
     * @return 
     */  
    public final String getAuthcode() {  
        return authcode;  
    }  
  
    /** 
     *  
     * @param authcode 
     */  
    public final void setAuthcode(String authcode) {  
        this.authcode = authcode;  
    }  
  
    
    public UsernamePasswordStrongCredential() {
        super();
    }

    public UsernamePasswordStrongCredential(String userName,
            String password) {
        super(userName, password);
    }
    
    public UsernamePasswordStrongCredential(String userName,
            String password,String loginType) {
        super(userName, password);
        setLoginType(loginType);
    }

    @Override  
    public boolean equals(final Object o) {  
        if (this == o) {  
            return true;  
        }  
        if (o == null || getClass() != o.getClass()) {  
            return false;  
        }  
  
        final UsernamePasswordStrongCredential that = (UsernamePasswordStrongCredential) o;  
  
        if (getPassword() != null ? !getPassword().equals(that.getPassword())  
                : that.getPassword() != null) {  
            return false;  
        }  
  
        if (getPassword() != null ? !getPassword().equals(that.getPassword())  
                : that.getPassword() != null) {  
            return false;  
        }  
        if (authcode != null ? !authcode.equals(that.getAuthcode())  
                : that.getAuthcode() != null)  
            return false;  
  
        return true;  
    }  
  
    @Override  
    public int hashCode() {  
        return new HashCodeBuilder().append(getUsername())  
                .append(getPassword()).append(authcode).toHashCode();  
    }  
}

  4.UserInfoPrincipalResolver.java

package org.jasig.cas.authentication.principal;


import javax.validation.constraints.NotNull;

import org.jasig.cas.authentication.Credential;
import org.jasig.cas.authentication.principal.DefaultPrincipalFactory;
import org.jasig.cas.authentication.principal.Principal;
import org.jasig.cas.authentication.principal.PrincipalFactory;
import org.jasig.cas.authentication.principal.PrincipalResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.hivecas.model.UsernamePasswordStrongCredential;

@Component("userInfoPrincipalResolver")
public class UserInfoPrincipalResolver implements PrincipalResolver{
	
	 protected final transient Logger logger = LoggerFactory.getLogger(this.getClass());
	
	   /**
     * Factory to create the principal type.
     **/
    @NotNull
    protected PrincipalFactory principalFactory = new DefaultPrincipalFactory();

	@Override
	public Principal resolve(Credential credential) {
		 logger.debug("Attempting to resolve a principal...");
	     final String principalId = extractPrincipalId(credential);
		UsernamePasswordStrongCredential  strongCredential=(UsernamePasswordStrongCredential) credential;
		 return this.principalFactory.createPrincipal(principalId, strongCredential.getAttributes());
	}

	@Override
	public boolean supports(Credential credential) {
		 return credential != null && credential.getId() != null;
	}
	
	  /**
     * Extracts the id of the user from the provided credential. This method should be overridden by subclasses to
     * achieve more sophisticated strategies for producing a principal ID from a credential.
     *
     * @param credential the credential provided by the user.
     * @return the username, or null if it could not be resolved.
     */
    protected String extractPrincipalId(final Credential credential) {
        return credential.getId();
    }

}

  5.页面2.0文件下的casServiceValidationSuccess.jsp改造

<%@ page session="false" contentType="application/xml; charset=UTF-8" %>
<%@ page import="java.util.*, java.util.Map.Entry" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
  <cas:authenticationSuccess>
<cas:user>${fn:escapeXml(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.id)}</cas:user>
   <c:if test="${fn:length(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes)> 0}">
           <cas:attributes>
               <c:forEach var="attr" items="${assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes}">
                   <cas:${fn:escapeXml(attr.key)}>${fn:escapeXml(attr.value)}</cas:${fn:escapeXml(attr.key)}>
               </c:forEach>
           </cas:attributes>
     </c:if> 
<c:if test="${not empty pgtIou}">
  <cas:proxyGrantingTicket>${pgtIou}</cas:proxyGrantingTicket>
</c:if>
<c:if test="${fn:length(assertion.chainedAuthentications) > 1}">
<cas:proxies>
<c:forEach var="proxy" items="${assertion.chainedAuthentications}" varStatus="loopStatus"  begin="0" end="${fn:length(assertion.chainedAuthentications)-2}"  step="1">
   <cas:proxy>${fn:escapeXml(proxy.principal.id)}</cas:proxy>
</c:forEach>
</cas:proxies>
</c:if>
 </cas:authenticationSuccess>
</cas:serviceResponse>

  6.客户端测试页面index.jsp的取值效果

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="org.jasig.cas.client.authentication.AttributePrincipal" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.lang.String" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>首页</title>
</head>
<body>
<div style="padding-left: 30%">
  用户名: <%=request.getAttribute("name")%>
<h1>订单系统<%=request.getLocalPort() %></h1>
   <% Cookie[] array =request.getCookies();
   String JSESSIONID="";
   if(array!=null)
	for(Cookie ck:array)
	{
		String ckName=ck.getName();
		if(ckName.equals("JSESSIONID"))
		{
			JSESSIONID=ck.getValue();
		}
	}
   %>
   <% 
    request.setCharacterEncoding("UTF-8");
    AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
    Map attributes = principal.getAttributes();
    String id=(String)attributes.get("id"); 
    String phone=(String)attributes.get("phone"); 
    String email=(String)attributes.get("email"); 
    %>
   Cookie中的JSESSIONID=<%=JSESSIONID%><br>
       用户id=<%=id%><br>
        用户手机号=<%=phone%><br>
         用户email=<%=email%><br>
   <br><br>
   <a href="http://passport.hivescm.com/cas/logout" >退出</a>
   </div>
</body>
</html>

  

原文地址:https://www.cnblogs.com/lvgg/p/7150450.html