cas 服务端、客服端详细配置

一、准备

    1、下载官方源码

       CAS-Server下载地址:https://www.apereo.org/projects/cas/download-cas

         CAS-Client下载地址:http://developer.jasig.org/cas-clients/

    版本:

  • CAS Server版本:cas-server-4.1.5
  • CAS Client版本:cas-client-3.3.3

  2、新建一个maven 聚合项目

 

  项目结构cas 服务端、客服端详细配置_第1张图片

 

   2.1、解压 cas-server-4.1.5后把cas-server-webapp所有文件拷贝到新建的maven项目中 

   2.2、pom.xml 配置源码

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0modelVersion>

  <groupId>xyz.casgroupId>
  <artifactId>xyz-casartifactId>
  <version>1.0.0.20170214version>
  <packaging>pompackaging>

  <name>xyz-casname>
  <url>http://maven.apache.orgurl>

  <properties>
    <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    <cas.version>4.1.5cas.version>
  properties>
  <modules>
      <module>xyz-cas-assemblemodule>
  modules>

  <dependencies>
    <dependency>
      <groupId>junitgroupId>
      <artifactId>junitartifactId>
      <version>3.8.1version>
      <scope>testscope>
    dependency>
    
     
            <dependency>
                <groupId>org.jasig.casgroupId>
                <artifactId>cas-server-webappartifactId>
                <version>${cas.version}version>
                <type>wartype>
                <scope>runtimescope>
            dependency>
            <dependency>
                <groupId>org.jasig.casgroupId>
                <artifactId>cas-server-webapp-supportartifactId>
                <version>${cas.version}version>
                <scope>runtimescope>
            dependency>
            <dependency>
                <groupId>org.jasig.casgroupId>
                <artifactId>cas-server-support-jdbcartifactId>
                <version>${cas.version}version>
                <scope>runtimescope>
            dependency>
            <dependency>
                <groupId>org.jasig.casgroupId>
                <artifactId>cas-server-support-restartifactId>
                <version>${cas.version}version>
                <scope>runtimescope>
            dependency>
            <dependency>
                  <groupId>org.jasig.casgroupId>
                  <artifactId>cas-server-integration-ehcacheartifactId>
                  <version>${cas.version}version>
                  <scope>runtimescope>
            dependency>
         
     
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatis-springartifactId>
            <version>1.2.3version>
        dependency>
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.3.1version>
        dependency>
        <dependency>
            <groupId>org.mybatis.generatorgroupId>
            <artifactId>mybatis-generator-coreartifactId>
            <version>1.3.2version>
        dependency>
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.38version>
        dependency>
        
        <dependency>
            <groupId>com.github.pagehelpergroupId>
            <artifactId>pagehelperartifactId>
            <version>4.0.1version>
        dependency>
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>druidartifactId>
            <version>1.0.17version>
        dependency>
        
            <dependency>
                <groupId>com.alibabagroupId>
                <artifactId>fastjsonartifactId>
                <version>1.2.7version>
            dependency>
            
            <dependency>
                <groupId>commons-httpclientgroupId>
                <artifactId>commons-httpclientartifactId>
                <version>3.1version>
            dependency>
            <dependency>
                <groupId>javax.servletgroupId>
                <artifactId>javax.servlet-apiartifactId>
                <version>3.1.0version>
            dependency>
dependencies>

    <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.pluginsgroupId>
        <artifactId>maven-war-pluginartifactId>
        <configuration>
          <warName>caswarName>
          <webResources>
            <resource>
              <directory>${basedir}/src/main/webapp/WEB-INFdirectory>
              <filtering>truefiltering>
              <targetPath>WEB-INFtargetPath>
              <includes>
                <include>**/web.xmlinclude>
              includes>
            resource>
          webResources>
        configuration>
      plugin>
      <plugin>
        <groupId>org.eclipse.jettygroupId>
        <artifactId>jetty-maven-pluginartifactId>
        <version>${maven-jetty-plugin.version}version>
        <configuration>
          <webApp>
            <contextPath>/cascontextPath>
          webApp>
        configuration>
      plugin>
    plugins>
  build>
project>
    
View Code

  2.3、打包成war放到tomcat目录下webapps中,启动tomcat 访问到cas,能访问到cas 准备工作也就完成!

二、修改cas配置

   1、打开 deployerConfigContext.xml 文件,找到 serviceRegistryDao 修改成下图所示。

 

    
    <bean id="serviceRegistryDao" class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl">
        <property name="registeredServices">
            <list>
                <bean class="org.jasig.cas.services.RegexRegisteredService">
                    <property name="id" value="0" />
                    <property name="name" value="HTTP and IMAP" />
                    <property name="description" value="Allows HTTP(S) and IMAP(S) protocols" />
                    <property name="serviceId" value="^(https?|imaps?)://.*" />
                    <property name="evaluationOrder" value="10000001" />
                bean>
            list>
        property>
    bean> 

  1.1、直接修改cas自带的服务文件,打开图上标记文件 

cas 服务端、客服端详细配置_第2张图片

 

修改serviceId为  ^(https?|imaps?)://.*   这样我们的客服端就能访问到cas服务端了

cas 服务端、客服端详细配置_第3张图片

 

 2、自定义用户登录验证

    2.1、找到deployerConfigContext.xml 文件 authenticationManager 把 primaryAuthenticationHandler 注释掉改成自己的验证类

    <bean id="authenticationManager" class="org.jasig.cas.authentication.PolicyBasedAuthenticationManager">
        <constructor-arg>
            <map>
                
                <entry key-ref="proxyAuthenticationHandler" value-ref="proxyPrincipalResolver" />
               
                <entry key-ref="ssoLoginHander" value-ref="primaryPrincipalResolver" />
            map>
        constructor-arg>

 

   2.2、加入注解context,在authenticationManager 它的上面添加

  <context:component-scan base-package="com.xyz.cas.*" />

完整的beans

<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:c="http://www.springframework.org/schema/c"       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:util="http://www.springframework.org/schema/util"       xmlns:sec="http://www.springframework.org/schema/security"
       xmlns:context="http://www.springframework.org/schema/context"
       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/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
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

2.2.1、找到deployerConfigContext.xml 文件 attributeRepository 注释掉

 

 2.3、在biz下新建文件,如图

cas 服务端、客服端详细配置_第4张图片

2.3.1、在login下新建SSOLoginHander类继承 AbstractPreAndPostProcessingAuthenticationHandler 用于登录验证,源码如下

package com.xyz.cas.login;

import java.security.GeneralSecurityException;
import java.util.List;

import javax.security.auth.login.FailedLoginException;

import org.jasig.cas.authentication.Credential;
import org.jasig.cas.authentication.HandlerResult;
import org.jasig.cas.authentication.PreventedException;
import org.jasig.cas.authentication.handler.support.AbstractPreAndPostProcessingAuthenticationHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.xyz.cas.common.md5.Md5Encrypt;
import com.xyz.cas.model.MyCredential;
import com.xyz.dal.mybatis.maps.UserMapper;
import com.xyz.dal.mybatis.model.User;
import com.xyz.dal.mybatis.model.UserExample;

/**
 *
 *
 * @author 
 *AbstractPreAndPostProcessingAuthenticationHandler
 */
@Service("ssoLoginHander")
public class SSOLoginHander extends AbstractPreAndPostProcessingAuthenticationHandler {
    
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    public UserMapper userMapper;
    
    /**
     * @param credential
     * @return
     * @see org.jasig.cas.authentication.AuthenticationHandler#supports(org.jasig.cas.authentication.Credential)
     */
    @Override
    public boolean supports(Credential credential) {
        return true;
    }

    /**
     * @param credential
     * @return
     * @throws GeneralSecurityException
     * @throws PreventedException
     * @see org.jasig.cas.authentication.handler.support.AbstractPreAndPostProcessingAuthenticationHandler#doAuthentication(org.jasig.cas.authentication.Credential)
     */
    @Override
    protected HandlerResult doAuthentication(Credential credential) throws GeneralSecurityException, PreventedException {
        MyCredential  credential2 =null;
        try
        {
        credential2= (MyCredential)credential;
        UserExample example=new UserExample();
        example.createCriteria().andLoginNameEqualTo(credential2.getUsername()).andPasswordEqualTo(Md5Encrypt.encrypt(credential2.getPassword()));
        Listlist= userMapper.selectByExample(example);
        if (list.isEmpty()&&list.size()==0)
        {
            throw new FailedLoginException("账号密码错误");
        }
            
        } catch (Exception e)
        {
            logger.info("web login fail, password does not match username on record. ");
            e.printStackTrace();
            throw new FailedLoginException(e.getMessage());
        }
    

        //验证是否登录成功
        //if(result.isFail()){
            logger.info("=============================================================");
        //    logger.info("who:"+username);
            logger.info("web login fail, password does not match username on record. ");
            logger.info("=============================================================");
            //throw new FailedLoginException("password does not match username on record.");
        //}
    //    upu.setUserId(result.getList().get(0).getBaseId());
        return createHandlerResult(credential, this.principalFactory.createPrincipal(credential2.getUsername()), null);
    }

}
View Code

在dal下的java 下新建 MyCredential 类 用于接收用户名密码

package com.xyz.dal.mybatis.model;

import org.jasig.cas.authentication.UsernamePasswordCredential;


public class MyCredential extends UsernamePasswordCredential {
    
    private static final long serialVersionUID = 2693123647112406019L;
    //
    private String serviceUrl;
    //类型
    private String idtype;  
    //用户ID
    private String userId;
    //票据
    private String tgt; 

    
    
    public String getUserId()
    {
        return userId;
    }

    public void setUserId(String userId)
    {
        this.userId = userId;
    }

    public String getTgt()
    {
        return tgt;
    }

    public void setTgt(String tgt)
    {
        this.tgt = tgt;
    }

    public static long getSerialversionuid()
    {
        return serialVersionUID;
    }

    public void setIdtype(String idtype)
    {
        this.idtype = idtype;
    }

    public String getServiceUrl()
    {
        return serviceUrl;
    }

    public void setServiceUrl(String serviceUrl)
    {
        this.serviceUrl = serviceUrl;
    }

    public String getIdtype()
    {
        return idtype;
    }
}
View Code

在 attribute 下 新建UserStubPersonAttributeDao类 用于登录验证成功后返回信息给客户端,这里我使用了mybatis 来操作数据库

package com.xyz.cas.attribute;

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

import org.jasig.services.persondir.IPersonAttributes;
import org.jasig.services.persondir.support.AttributeNamedPersonImpl;
import org.jasig.services.persondir.support.StubPersonAttributeDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.xyz.dal.mybatis.maps.UserMapper;
import com.xyz.dal.mybatis.model.MyCredential;
import com.xyz.dal.mybatis.model.User;
import com.xyz.dal.mybatis.model.UserExample;


@Service("attributeRepository")
public class UserStubPersonAttributeDao extends StubPersonAttributeDao {
    
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
     @Autowired
        public UserMapper userMapper;

    /**
     * @param uid
     * @return
     * @see org.jasig.services.persondir.support.StubPersonAttributeDao#getPerson(java.lang.String)
     */
    @Override
    public IPersonAttributes getPerson(String uid) {
        
        Map> attributes = new HashMap>();
        
        MyCredential mycredential = JSONObject.parseObject(uid, MyCredential.class);
        
        UserExample example=new UserExample();
        example.createCriteria().andLoginNameEqualTo(mycredential.getUsername());
        
        Listlist= userMapper.selectByExample(example);
        
        mycredential.setUserId(list.get(0).getId());
        
        String userInfo=JSONObject.toJSONString(list);
        attributes.put("userInfo", Collections.singletonList((Object)userInfo));
       // attributes.put("permissionInfo", Collections.singletonList((Object)permissionInfo));
        //attributes.put("roleInfo", Collections.singletonList((Object)roleInfo));
        return new AttributeNamedPersonImpl(attributes);
    }

}
View Code

在assemble新建 org.jasig.cas.authentication.principal 包 新建类 PersonDirectoryPrincipalResolver

cas 服务端、客服端详细配置_第5张图片

源码如下

/*
 * Licensed to Apereo under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Apereo licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License.  You may obtain a
 * copy of the License at the following location:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.jasig.cas.authentication.principal;

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

import javax.validation.constraints.NotNull;

import org.jasig.cas.authentication.Credential;
import org.jasig.services.persondir.IPersonAttributeDao;
import org.jasig.services.persondir.IPersonAttributes;
import org.jasig.services.persondir.support.StubPersonAttributeDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;
import com.xyz.dal.mybatis.model.MyCredential;

/**
 * Resolves principals by querying a data source using the Jasig
 * http://developer.jasig.org/projects/person-directory/1.5.0-SNAPSHOT/apidocs/">Person Directory API.
 * The {@link org.jasig.cas.authentication.principal.Principal#getAttributes()} are populated by the results of the
 * query and the principal ID may optionally be set by proving an attribute whose first non-null value is used;
 * otherwise the credential ID is used for the principal ID.
 *
 * @author Marvin S. Addison
 * @since 4.0.0
 *
 */
public class PersonDirectoryPrincipalResolver implements PrincipalResolver {

    /** Log instance. */
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    private boolean returnNullIfNoAttributes;

    /** Repository of principal attributes to be retrieved. */
    @NotNull
    private IPersonAttributeDao attributeRepository = new StubPersonAttributeDao(new HashMap>());

    /** Factory to create the principal type. **/
    @NotNull
    private PrincipalFactory principalFactory = new DefaultPrincipalFactory();

    /** Optional principal attribute name. */
    private String principalAttributeName;
    /**
     * @param credential
     * @return
     * @see org.jasig.cas.authentication.principal.PrincipalResolver#supports(org.jasig.cas.authentication.Credential)
     */
    public boolean supports(Credential credential)
    {
        return true;
    }
    /**
     * @param credential
     * @return
     * @see org.jasig.cas.authentication.principal.PrincipalResolver#resolve(org.jasig.cas.authentication.Credential)
     */
    public Principal resolve(Credential credential)
    {
         logger.debug("Attempting to resolve a principal...");

            String principalId = extractPrincipalId(credential);

            if (principalId == null) {
                logger.debug("Got null for extracted principal ID; returning null.");
                return null;
            }

            logger.debug("Creating SimplePrincipal for [{}]", principalId);
            final MyCredential  upu = (MyCredential)credential;;
            String principalIdExtend = JSONObject.toJSONString(upu);
            final IPersonAttributes personAttributes = this.attributeRepository.getPerson(principalIdExtend);
            final Map> attributes;

            if (personAttributes == null) {
                attributes = null;
            } else {
                attributes = personAttributes.getAttributes();
            }

            if (attributes == null || attributes.isEmpty()) {
                if (!this.returnNullIfNoAttributes) {
                    return this.principalFactory.createPrincipal(principalId);
                }
                return null;
            }

            final Map convertedAttributes = new HashMap();
            for (final Map.Entry> entry : attributes.entrySet()) {
                final String key = entry.getKey();
                final List values = entry.getValue();
                if (key.equalsIgnoreCase(this.principalAttributeName)) {
                    if (values.isEmpty()) {
                        logger.debug("{} is empty, using {} for principal", this.principalAttributeName, principalId);
                    } else {
                        principalId = values.get(0).toString();
                        logger.debug(
                                "Found principal attribute value {}; removing {} from attribute map.",
                                principalId,
                                this.principalAttributeName);
                    }
                } else {
                    convertedAttributes.put(key, values.size() == 1 ? values.get(0) : values);
                }
            }
           return this.principalFactory.createPrincipal(principalId, convertedAttributes);
    }

    public final void setAttributeRepository(final IPersonAttributeDao attributeRepository) {
        this.attributeRepository = attributeRepository;
    }

    public void setReturnNullIfNoAttributes(final boolean returnNullIfNoAttributes) {
        this.returnNullIfNoAttributes = returnNullIfNoAttributes;
    }

    /**
     * Sets the name of the attribute whose first non-null value should be used for the principal ID.
     *
     * @param attribute Name of attribute containing principal ID.
     */
    public void setPrincipalAttributeName(final String attribute) {
        this.principalAttributeName = attribute;
    }

    /**
     * Sets principal factory to create principal objects.
     *
     * @param principalFactory the principal factory
     */
    public void setPrincipalFactory(final PrincipalFactory principalFactory) {
        this.principalFactory = principalFactory;
    }

    /**
     * Extracts the id of the user from the provided credential. This method should be overridded 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();
    }


} 
     
    View Code 
    
   

修改 webflow下面的 login-webflow.xml,找到 credential 修改成上面定义的类,用于接收页面输入的用户名密码


<var name="credential" class="com.xyz.cas.model.MyCredential"/>

<view-state id="viewLoginForm" view="casLoginView" model="credential"> <binder> <binding property="username" required="true"/> <binding property="password" required="true"/> binder> <on-entry> <set name="viewScope.commandName" value="'credential'"/> on-entry> <transition on="submit" bind="true" validate="true" to="realSubmit"/> view-state>

修改完成自定义类路径后在当前login-webflow.xml中找到 节点id serviceUnauthorizedCheck  修改如下

    <end-state id="viewServiceErrorView" view="serviceErrorView"/>
 

<end-state id="viewServiceSsoErrorView" view="viewServiceSsoErrorView" /> <global-transitions> <transition to="viewLoginForm" on-exception="org.jasig.cas.services.UnauthorizedSsoServiceException"/> <transition to="viewServiceErrorView" on-exception="org.springframework.webflow.execution.repository.NoSuchFlowExecutionException"/>
<transition to="viewServiceErrorView" on-exception="org.jasig.cas.services.UnauthorizedServiceException"/> global-transitions>

ps:这部分不修改 使用tomcat启动访问后 报错 :CAS is Unavailable There was an error trying to complete your request. Please notify your support desk or try again.

查看日志显示:Unable to load class ' com.xyz.cas.model.MyCredential'

完整的 login-webflow.xml 源码

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

<flow xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns="http://www.springframework.org/schema/webflow"
      xsi:schemaLocation="http://www.springframework.org/schema/webflow
                          http://www.springframework.org/schema/webflow/spring-webflow.xsd">

    <var name="credential" class="com.xyz.cas.model.MyCredential"/>
    <on-start>
        <evaluate expression="initialFlowSetupAction"/>
    on-start>

    <action-state id="ticketGrantingTicketCheck">
        <evaluate expression="ticketGrantingTicketCheckAction"/>
        <transition on="notExists" to="gatewayRequestCheck"/>
        <transition on="invalid" to="terminateSession"/>
        <transition on="valid" to="hasServiceCheck"/>
    action-state>

    <action-state id="terminateSession">
        <evaluate expression="terminateSessionAction.terminate(flowRequestContext)"/>
        <transition to="gatewayRequestCheck"/>
    action-state>

    <decision-state id="gatewayRequestCheck">
        <if test="requestParameters.gateway != '' and requestParameters.gateway != null and flowScope.service != null"
            then="gatewayServicesManagementCheck" else="serviceAuthorizationCheck"/>
    decision-state>

    <decision-state id="hasServiceCheck">
        <if test="flowScope.service != null" then="renewRequestCheck" else="viewGenericLoginSuccess"/>
    decision-state>

    <decision-state id="renewRequestCheck">
        <if test="requestParameters.renew != '' and requestParameters.renew != null" then="serviceAuthorizationCheck"
            else="generateServiceTicket"/>
    decision-state>

    
    <action-state id="serviceAuthorizationCheck">
        <evaluate expression="serviceAuthorizationCheck"/>
        <transition to="generateLoginTicket"/>
    action-state>

    
    <decision-state id="warn">
        <if test="flowScope.warnCookieValue" then="showWarningView" else="redirect"/>
    decision-state>

    

    <action-state id="generateLoginTicket">
        <evaluate expression="generateLoginTicketAction.generate(flowRequestContext)"/>
        <transition on="generated" to="viewLoginForm"/>
    action-state>

    <view-state id="viewLoginForm" view="casLoginView" model="credential">
        <binder>
            <binding property="username" required="true"/>
            <binding property="password" required="true"/>
        binder>
        <on-entry>
            <set name="viewScope.commandName" value="'credential'"/>

            
        on-entry>
        <transition on="submit" bind="true" validate="true" to="realSubmit"/>
    view-state>

    <action-state id="realSubmit">
        <evaluate
                expression="authenticationViaFormAction.submit(flowRequestContext, flowScope.credential, messageContext)"/>
        <transition on="warn" to="warn"/>
        
        <transition on="success" to="sendTicketGrantingTicket"/>
        <transition on="successWithWarnings" to="showMessages"/>
        <transition on="authenticationFailure" to="handleAuthenticationFailure"/>
        <transition on="error" to="generateLoginTicket"/>
    action-state>

    

    <view-state id="showMessages" view="casLoginMessageView">
        <on-entry>
            <evaluate expression="sendTicketGrantingTicketAction"/>
            <set name="requestScope.messages" value="messageContext.allMessages"/>
        on-entry>
        <transition on="proceed" to="serviceCheck"/>
    view-state>

    <action-state id="handleAuthenticationFailure">
        <evaluate expression="authenticationExceptionHandler.handle(currentEvent.attributes.error, messageContext)"/>
        <transition on="AccountDisabledException" to="casAccountDisabledView"/>
        <transition on="AccountLockedException" to="casAccountLockedView"/>
        <transition on="AccountPasswordMustChangeException" to="casMustChangePassView"/>
        <transition on="CredentialExpiredException" to="casExpiredPassView"/>
        <transition on="InvalidLoginLocationException" to="casBadWorkstationView"/>
        <transition on="InvalidLoginTimeException" to="casBadHoursView"/>
        <transition on="FailedLoginException" to="generateLoginTicket"/>
        <transition on="AccountNotFoundException" to="generateLoginTicket"/>
        <transition on="UNKNOWN" to="generateLoginTicket"/>
    action-state>

    <action-state id="sendTicketGrantingTicket">
        <evaluate expression="sendTicketGrantingTicketAction"/>
        <transition to="serviceCheck"/>
    action-state>

    <decision-state id="serviceCheck">
        <if test="flowScope.service != null" then="generateServiceTicket" else="viewGenericLoginSuccess"/>
    decision-state>

    <action-state id="generateServiceTicket">
        <evaluate expression="generateServiceTicketAction"/>
        <transition on="success" to="warn"/>
        <transition on="authenticationFailure" to="handleAuthenticationFailure"/>
        <transition on="error" to="generateLoginTicket"/>
        <transition on="gateway" to="gatewayServicesManagementCheck"/>
    action-state>

    <action-state id="gatewayServicesManagementCheck">
        <evaluate expression="gatewayServicesManagementCheck"/>
        <transition on="success" to="redirect"/>
    action-state>

    <action-state id="redirect">
        <evaluate expression="flowScope.service.getResponse(requestScope.serviceTicketId)"
                  result-type="org.jasig.cas.authentication.principal.Response" result="requestScope.response"/>
        <transition to="postRedirectDecision"/>
    action-state>

    <decision-state id="postRedirectDecision">
        <if test="requestScope.response.responseType.name() == 'POST'" then="postView" else="redirectView"/>
    decision-state>

    

    <end-state id="viewGenericLoginSuccess" view="casGenericSuccessView">
        <on-entry>
            <evaluate expression="genericSuccessViewAction.getAuthenticationPrincipal(flowScope.ticketGrantingTicketId)"
                      result="requestScope.principal"
                      result-type="org.jasig.cas.authentication.principal.Principal"/>
        on-entry>
    end-state>


    
    <end-state id="showWarningView" view="casConfirmView"/>


    
    <end-state id="abstactPasswordChangeView">
        <on-entry>
            <set name="flowScope.passwordPolicyUrl" value="passwordPolicy.passwordPolicyUrl"/>
        on-entry>
    end-state>
    <end-state id="casExpiredPassView" view="casExpiredPassView" parent="#abstactPasswordChangeView"/>
    <end-state id="casMustChangePassView" view="casMustChangePassView" parent="#abstactPasswordChangeView"/>
    <end-state id="casAccountDisabledView" view="casAccountDisabledView"/>
    <end-state id="casAccountLockedView" view="casAccountLockedView"/>
    <end-state id="casBadHoursView" view="casBadHoursView"/>
    <end-state id="casBadWorkstationView" view="casBadWorkstationView"/>

    <end-state id="postView" view="postResponseView">
        <on-entry>
            <set name="requestScope.parameters" value="requestScope.response.attributes"/>
            <set name="requestScope.originalUrl" value="flowScope.service.id"/>
        on-entry>
    end-state>

    
    <end-state id="redirectView" view="externalRedirect:#{requestScope.response.url}"/>

    <end-state id="viewServiceErrorView" view="serviceErrorView"/>

    
    <end-state id="viewServiceSsoErrorView" view="viewServiceSsoErrorView" />

    <global-transitions>
        <transition to="viewLoginForm" on-exception="org.jasig.cas.services.UnauthorizedSsoServiceException"/>
        <transition to="viewServiceErrorView"
                    on-exception="org.springframework.webflow.execution.repository.NoSuchFlowExecutionException"/>
        <transition to="viewServiceErrorView" on-exception="org.jasig.cas.services.UnauthorizedServiceException"/>
    global-transitions>
flow>
View Code

打开如图所示的文件

cas 服务端、客服端详细配置_第6张图片

 

 在 ${fn:escapeXml(principal.id)} 后面添加下面这段,添加后客服端才能接收返回的信息

if test="${fn:length(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes) > 0}">
            
                
                    ${fn:escapeXml(attr.value)}
                
            
        if>

 三、客服端配置 

客户端项目结构如下

cas 服务端、客服端详细配置_第7张图片

1、在客服端pom.xml中增加一下依赖包

            
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-coreartifactId>
            <version>1.2.1version>
        dependency>
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-webartifactId>
            <version>1.2.1version>
        dependency>
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-ehcacheartifactId>
            <version>1.2.1version>
        dependency>
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-springartifactId>
            <version>1.2.1version>
        dependency>
         <dependency>
                <groupId>org.apache.shirogroupId>
                <artifactId>shiro-casartifactId>
                <version>1.2.4version>
       dependency>

 2、在xyz-domo-web 下src\main\resources 下新建包 cache,在cache 下新建文件 ehcache.xsd 

xml version="1.0" encoding="UTF-8" standalone="no"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" version="1.7">

    <xs:element name="ehcache">
        <xs:complexType>
            <xs:sequence>
                <xs:element maxOccurs="1" minOccurs="0" ref="diskStore"/>
                <xs:element maxOccurs="1" minOccurs="0" ref="sizeOfPolicy"/>
                <xs:element maxOccurs="1" minOccurs="0" ref="transactionManagerLookup"/>
                <xs:element maxOccurs="1" minOccurs="0" ref="cacheManagerEventListenerFactory"/>
                <xs:element maxOccurs="unbounded" minOccurs="0" ref="cacheManagerPeerProviderFactory"/>
                <xs:element maxOccurs="unbounded" minOccurs="0" ref="cacheManagerPeerListenerFactory"/>
                <xs:element maxOccurs="1" minOccurs="0" ref="terracottaConfig"/>
                <xs:element maxOccurs= "1" minOccurs="0" ref="defaultCache"/>
                <xs:element maxOccurs="unbounded" minOccurs="0" ref="cache"/>
            xs:sequence>
            <xs:attribute name="name" use="optional"/>
            <xs:attribute default="true" name="updateCheck" type="xs:boolean" use="optional"/>
            <xs:attribute default="autodetect" name="monitoring" type="monitoringType" use="optional"/>
            <xs:attribute default="true" name="dynamicConfig" type="xs:boolean" use="optional"/>
            <xs:attribute default="15" name="defaultTransactionTimeoutInSeconds" type="xs:integer" use="optional"/>
            <xs:attribute default="0" name="maxBytesLocalHeap" type="memoryUnitOrPercentage" use="optional"/>
            <xs:attribute default="0" name="maxBytesLocalOffHeap" type="memoryUnit" use="optional"/>
            <xs:attribute default="0" name="maxBytesLocalDisk" type="memoryUnit" use="optional"/>
        xs:complexType>
    xs:element>
    <xs:element name="diskStore">
        <xs:complexType>
            <xs:attribute name="path" use="optional"/>
        xs:complexType>
    xs:element>
    <xs:element name="transactionManagerLookup">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        xs:complexType>
    xs:element>
    <xs:element name="cacheManagerEventListenerFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        xs:complexType>
    xs:element>
    <xs:element name="cacheManagerPeerProviderFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        xs:complexType>
    xs:element>
    <xs:element name="cacheManagerPeerListenerFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        xs:complexType>
    xs:element>
    <xs:element name="terracottaConfig">
        <xs:complexType>
            <xs:sequence>
                <xs:element maxOccurs="1" minOccurs="0" name="tc-config">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:any maxOccurs="unbounded" minOccurs="0" processContents="skip"/>
                        xs:sequence>
                    xs:complexType>
                xs:element>
            xs:sequence>
            <xs:attribute default="localhost:9510" name="url" use="optional"/>
            <xs:attribute name="rejoin" type="xs:boolean" use="optional" default="false"/>
        xs:complexType>
    xs:element>
    
    <xs:element name="defaultCache">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheEventListenerFactory"/>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheExtensionFactory"/>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheLoaderFactory"/>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheDecoratorFactory"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="bootstrapCacheLoaderFactory"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="cacheExceptionHandlerFactory"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="pinning"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="terracotta"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="cacheWriter"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="copyStrategy"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="elementValueComparator"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="sizeOfPolicy"/>
            xs:sequence>
            <xs:attribute name="diskExpiryThreadIntervalSeconds" type="xs:integer" use="optional"/>
            <xs:attribute name="diskSpoolBufferSizeMB" type="xs:integer" use="optional"/>
            <xs:attribute name="diskPersistent" type="xs:boolean" use="optional"/>
            <xs:attribute name="diskAccessStripes" type="xs:integer" use="optional" default="1"/>
            <xs:attribute name="eternal" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="maxElementsInMemory" type="xs:integer" use="optional"/>
            <xs:attribute name="maxEntriesLocalHeap" type="xs:integer" use="optional"/>
            <xs:attribute name="clearOnFlush" type="xs:boolean" use="optional"/>
            <xs:attribute name="memoryStoreEvictionPolicy" type="xs:string" use="optional"/>
            <xs:attribute name="overflowToDisk" type="xs:boolean" use="optional"/>
            <xs:attribute name="timeToIdleSeconds" type="xs:integer" use="optional"/>
            <xs:attribute name="timeToLiveSeconds" type="xs:integer" use="optional"/>
            <xs:attribute name="maxElementsOnDisk" type="xs:integer" use="optional"/>
            <xs:attribute name="maxEntriesLocalDisk" type="xs:integer" use="optional"/>
            <xs:attribute name="transactionalMode" type="transactionalMode" use="optional" default="off"/>
            <xs:attribute name="statistics" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="copyOnRead" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="copyOnWrite" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="cacheLoaderTimeoutMillis" type="xs:integer" use="optional" default="0"/>
            <xs:attribute name="overflowToOffHeap" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="maxMemoryOffHeap" type="xs:string" use="optional"/>
        xs:complexType>
    xs:element>
    <xs:element name="cache">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheEventListenerFactory"/>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheExtensionFactory"/>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheLoaderFactory"/>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheDecoratorFactory"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="bootstrapCacheLoaderFactory"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="cacheExceptionHandlerFactory"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="pinning"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="terracotta"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="cacheWriter"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="copyStrategy"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="searchable"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="elementValueComparator"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="sizeOfPolicy"/>
            xs:sequence>
            <xs:attribute name="diskExpiryThreadIntervalSeconds" type="xs:integer" use="optional"/>
            <xs:attribute name="diskSpoolBufferSizeMB" type="xs:integer" use="optional"/>
            <xs:attribute name="diskPersistent" type="xs:boolean" use="optional"/>
            <xs:attribute name="diskAccessStripes" type="xs:integer" use="optional" default="1"/>
            <xs:attribute name="eternal" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="maxElementsInMemory" type="xs:integer" use="optional"/>
            <xs:attribute name="maxEntriesLocalHeap" type="xs:integer" use="optional"/>
            <xs:attribute name="memoryStoreEvictionPolicy" type="xs:string" use="optional"/>
            <xs:attribute name="clearOnFlush" type="xs:boolean" use="optional"/>
            <xs:attribute name="name" type="xs:string" use="required"/>
            <xs:attribute name="overflowToDisk" type="xs:boolean" use="optional"/>
            <xs:attribute name="timeToIdleSeconds" type="xs:integer" use="optional"/>
            <xs:attribute name="timeToLiveSeconds" type="xs:integer" use="optional"/>
            <xs:attribute name="maxElementsOnDisk" type="xs:integer" use="optional"/>
            <xs:attribute name="maxEntriesLocalDisk" type="xs:integer" use="optional"/>
            <xs:attribute name="transactionalMode" type="transactionalMode" use="optional" default="off" />
            <xs:attribute name="statistics" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="copyOnRead" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="copyOnWrite" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="logging" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="cacheLoaderTimeoutMillis" type="xs:integer" use="optional" default="0"/>
            <xs:attribute name="overflowToOffHeap" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="maxMemoryOffHeap" type="xs:string" use="optional"/>
            <xs:attribute default="0" name="maxBytesLocalHeap" type="memoryUnitOrPercentage" use="optional"/>
            <xs:attribute default="0" name="maxBytesLocalOffHeap" type="memoryUnitOrPercentage" use="optional"/>
            <xs:attribute default="0" name="maxBytesLocalDisk" type="memoryUnitOrPercentage" use="optional"/>
        xs:complexType>
    xs:element>
    <xs:element name="cacheEventListenerFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
            <xs:attribute name="listenFor" use="optional" type="notificationScope" default="all"/>
        xs:complexType>
    xs:element>
    <xs:element name="bootstrapCacheLoaderFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        xs:complexType>
    xs:element>
    <xs:element name="cacheExtensionFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        xs:complexType>
    xs:element>
    <xs:element name="cacheExceptionHandlerFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        xs:complexType>
    xs:element>
    <xs:element name="cacheLoaderFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        xs:complexType>
    xs:element>
    <xs:element name="cacheDecoratorFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        xs:complexType>
    xs:element>
    <xs:element name="searchAttribute">
        <xs:complexType>
            <xs:attribute name="name" use="required" type="xs:string"/>
            <xs:attribute name="expression" type="xs:string"/>
            <xs:attribute name="class" type="xs:string"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        xs:complexType>
    xs:element>

    <xs:element name="searchable">
      <xs:complexType>
        <xs:sequence>
          <xs:element minOccurs="0" maxOccurs="unbounded" ref="searchAttribute"/>
        xs:sequence>
        <xs:attribute name="keys" use="optional" type="xs:boolean" default="true"/>
        <xs:attribute name="values" use="optional" type="xs:boolean" default="true"/>
      xs:complexType>
    xs:element>

    <xs:element name="pinning">
        <xs:complexType>
            <xs:attribute name="store" use="required" type="pinningStoreType"/>
        xs:complexType>
    xs:element>

    <xs:element name="terracotta">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="0" maxOccurs="1" ref="nonstop"/>
            xs:sequence>
            <xs:attribute name="clustered" use="optional" type="xs:boolean" default="true"/>
            <xs:attribute name="valueMode" use="optional" type="terracottaCacheValueType" default="serialization"/>
            <xs:attribute name="coherentReads" use="optional" type="xs:boolean" default="true"/>
            <xs:attribute name="localKeyCache" use="optional" type="xs:boolean" default="false"/>
            <xs:attribute name="localKeyCacheSize" use="optional" type="xs:positiveInteger" default="300000"/>
            <xs:attribute name="orphanEviction" use="optional" type="xs:boolean" default="true"/>
            <xs:attribute name="orphanEvictionPeriod" use="optional" type="xs:positiveInteger" default="4"/>
            <xs:attribute name="copyOnRead" use="optional" type="xs:boolean" default="false"/>
            <xs:attribute name="coherent" use="optional" type="xs:boolean" default="false"/>
            <xs:attribute name="consistency" use="optional" type="consistencyType" default="eventual"/>
            <xs:attribute name="synchronousWrites" use="optional" type="xs:boolean" default="false"/>
            <xs:attribute name="storageStrategy" use="optional" type="storageStrategyType" default="DCV2"/>
            <xs:attribute name="concurrency" use="optional" type="xs:nonNegativeInteger" default="0"/>
            <xs:attribute name="localCacheEnabled" use="optional" type="xs:boolean" default="true"/>
            <xs:attribute name="compressionEnabled" use="optional" type="xs:boolean" default="false"/>
        xs:complexType>
    xs:element>
    <xs:simpleType name="consistencyType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="strong" />
            <xs:enumeration value="eventual" />
        xs:restriction>
    xs:simpleType>
    <xs:element name="nonstop">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="0" maxOccurs="1" ref="timeoutBehavior"/>
            xs:sequence>
            <xs:attribute name="enabled" use="optional" type="xs:boolean" default="true"/>
            <xs:attribute name="immediateTimeout" use="optional" type="xs:boolean" default="false"/>
            <xs:attribute name="timeoutMillis" use="optional" type="xs:positiveInteger" default="30000"/>
        xs:complexType>
    xs:element>
    <xs:element name="timeoutBehavior">
        <xs:complexType>
            <xs:attribute name="type" use="optional" type="timeoutBehaviorType" default="exception"/>
            <xs:attribute name="properties" use="optional" default=""/>
            <xs:attribute name="propertySeparator" use="optional" default=","/>
        xs:complexType>
    xs:element>
    <xs:simpleType name="timeoutBehaviorType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="noop" />
            <xs:enumeration value="exception" />
            <xs:enumeration value="localReads" />
        xs:restriction>
    xs:simpleType>
    <xs:simpleType name="monitoringType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="autodetect"/>
            <xs:enumeration value="on"/>
            <xs:enumeration value="off"/>
        xs:restriction>
    xs:simpleType>
    <xs:simpleType name="pinningStoreType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="localHeap" />
            <xs:enumeration value="localMemory" />
            <xs:enumeration value="inCache" />
        xs:restriction>
    xs:simpleType>
    <xs:simpleType name="terracottaCacheValueType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="serialization" />
            <xs:enumeration value="identity" />
        xs:restriction>
    xs:simpleType>
    <xs:simpleType name="storageStrategyType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="classic" />
            <xs:enumeration value="DCV2" />
        xs:restriction>
    xs:simpleType>

    <xs:simpleType name="transactionalMode">
        <xs:restriction base="xs:string">
            <xs:enumeration value="off"/>
            <xs:enumeration value="xa_strict"/>
            <xs:enumeration value="xa"/>
            <xs:enumeration value="local"/>
        xs:restriction>
    xs:simpleType>

    <xs:element name="cacheWriter">
        <xs:complexType>
            <xs:sequence >
                <xs:element minOccurs="0" maxOccurs="1" ref="cacheWriterFactory"/>
            xs:sequence>
            <xs:attribute name="writeMode" use="optional" type="writeModeType" default="write-through"/>
            <xs:attribute name="notifyListenersOnException" use="optional" type="xs:boolean" default="false"/>
            <xs:attribute name="minWriteDelay" use="optional" type="xs:nonNegativeInteger" default="1"/>
            <xs:attribute name="maxWriteDelay" use="optional" type="xs:nonNegativeInteger" default="1"/>
            <xs:attribute name="rateLimitPerSecond" use="optional" type="xs:nonNegativeInteger" default="0"/>
            <xs:attribute name="writeCoalescing" use="optional" type="xs:boolean" default="false"/>
            <xs:attribute name="writeBatching" use="optional" type="xs:boolean" default="false"/>
            <xs:attribute name="writeBatchSize" use="optional" type="xs:positiveInteger" default="1"/>
            <xs:attribute name="retryAttempts" use="optional" type="xs:nonNegativeInteger" default="0"/>
            <xs:attribute name="retryAttemptDelaySeconds" use="optional" type="xs:nonNegativeInteger" default="1"/>
            <xs:attribute name="writeBehindConcurrency" use="optional" type="xs:nonNegativeInteger" default="1"/>
            <xs:attribute name="writeBehindMaxQueueSize" use="optional" type="xs:nonNegativeInteger" default="0"/>
        xs:complexType>
    xs:element>
    <xs:simpleType name="writeModeType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="write-through" />
            <xs:enumeration value="write-behind" />
        xs:restriction>
    xs:simpleType>
    <xs:element name="cacheWriterFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        xs:complexType>
    xs:element>

    <xs:element name="copyStrategy">
        <xs:complexType>
            <xs:attribute name="class" use="required" type="xs:string" />
        xs:complexType>
    xs:element>

    <xs:element name="elementValueComparator">
        <xs:complexType>
            <xs:attribute name="class" use="required" type="xs:string" />
        xs:complexType>
    xs:element>

    <xs:element name="sizeOfPolicy">
        <xs:complexType>
            <xs:attribute name="maxDepth" use="required" type="xs:integer" />
            <xs:attribute name="maxDepthExceededBehavior" use="optional" default="continue" type="maxDepthExceededBehavior" />
        xs:complexType>
    xs:element>

    <xs:simpleType name="maxDepthExceededBehavior">
        <xs:restriction base="xs:string">
            <xs:enumeration value="continue"/>
            <xs:enumeration value="abort"/>
        xs:restriction>
    xs:simpleType>

    <xs:simpleType name="notificationScope">
        <xs:restriction base="xs:string">
            <xs:enumeration value="local"/>
            <xs:enumeration value="remote"/>
            <xs:enumeration value="all"/>
        xs:restriction>
    xs:simpleType>
    <xs:simpleType name="memoryUnit">
        <xs:restriction base="xs:token">
            <xs:pattern value="[0-9]+[bBkKmMgG]?"/>
        xs:restriction>
    xs:simpleType>
    <xs:simpleType name="memoryUnitOrPercentage">
        <xs:restriction base="xs:token">
            <xs:pattern value="([0-9]+[bBkKmMgG]?|100%|[0-9]{1,2}%)"/>
        xs:restriction>
    xs:simpleType>
xs:schema>
View Code

2.1、新建shiro-cache.xml 文件 

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
     http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-3.0.xsd
     http://www.springframework.org/schema/util
     http://www.springframework.org/schema/util/spring-util-3.0.xsd"
    default-lazy-init="true">
    
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        
        <property name="loginUrl" value="${sso.shiro.login.url}" />
        
        
        <property name="filters">
            <util:map>
                
                <entry key="casFilter" value-ref="casFilter"/>
                <entry key="authc">
                    <bean class="com.xyz.domo.filter.FormAuthenticationFilterExt">bean>
                entry>
            util:map>
            
        property> 
        <property name="filterChainDefinitions">
            <value>                
                
                
                /cas = casFilter
                /version/uploadImage = anon
                /anon/** = anon
                /druid/** = anon
                /** = authc

            value>
        property>
    bean>
    
    <bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
        
        <property name="failureUrl" value="/error.jsp"/>
    bean>
    
    <bean id="casRealm" class="com.xyz.domo.controller.realm.MyCasRealm">
        <property name="defaultRoles" value="ROLE_USER"/>        
        <property name="casServerUrlPrefix" value="${sso.cas.url.prefix}"/>
        
        <property name="casService" value="${sso.callback.url}"/>
        
    bean>
    
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">      


        <property name="realm" ref="casRealm"/>
        <property name="subjectFactory" ref="casSubjectFactory"/>
    bean>
    
    
    <bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory"/>

    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
    
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    bean>
    
    
    <bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">  
        <property name="configLocation" value="classpath:cache/shiro-cache.xml"/>  
    bean>  
    <bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">  
        <property name="cacheManager" ref="cacheManagerFactory"/>  
    bean>

    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
        <property name="arguments" ref="securityManager"/>
    bean>
    
    
    <bean id="handlerExceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <prop key="org.apache.shiro.authz.UnauthorizedException">authErrorprop>
                <prop key="org.apache.shiro.authz.AuthorizationException">authErrorprop>
               
            props>
        property>
    bean> 
beans>
View Code

3、在src\main\resources 下新建包 spring,在spring下新建 shiro-spring.xml 

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
     http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-3.0.xsd
     http://www.springframework.org/schema/util
     http://www.springframework.org/schema/util/spring-util-3.0.xsd"
    default-lazy-init="true">
    
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        
        <property name="loginUrl" value="${sso.shiro.login.url}" />
        
        
        <property name="filters">
            <util:map>
                
                <entry key="casFilter" value-ref="casFilter"/>
                <entry key="authc">
                    <bean class="com.xyz.domo.filter.FormAuthenticationFilterExt">bean>
                entry>
            util:map>
            
        property> 
        <property name="filterChainDefinitions">
            <value>                
                
                
                /cas = casFilter
                /version/uploadImage = anon
                /anon/** = anon
                /druid/** = anon
                /** = authc

            value>
        property>
    bean>
    
    <bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
        
        <property name="failureUrl" value="/error.jsp"/>
    bean>
    
    <bean id="casRealm" class="com.xyz.domo.controller.realm.MyCasRealm">
        <property name="defaultRoles" value="ROLE_USER"/>        
        <property name="casServerUrlPrefix" value="${sso.cas.url.prefix}"/>
        
        <property name="casService" value="${sso.callback.url}"/>
        
    bean>
    
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">      


        <property name="realm" ref="casRealm"/>
        <property name="subjectFactory" ref="casSubjectFactory"/>
    bean>
    
    
    <bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory"/>

    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
    
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    bean>
    
    
    <bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">  
        <property name="configLocation" value="classpath:cache/shiro-cache.xml"/>  
    bean>  
    <bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">  
        <property name="cacheManager" ref="cacheManagerFactory"/>  
    bean>

    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
        <property name="arguments" ref="securityManager"/>
    bean>
    
    
    <bean id="handlerExceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <prop key="org.apache.shiro.authz.UnauthorizedException">authErrorprop>
                <prop key="org.apache.shiro.authz.AuthorizationException">authErrorprop>
               
            props>
        property>
    bean> 
beans>
View Code

3.1、新建文件 spring-cas.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
     http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-3.0.xsd
     http://www.springframework.org/schema/util
     http://www.springframework.org/schema/util/spring-util-3.0.xsd"
    default-lazy-init="true">

    <context:component-scan base-package="com.xyz.*" />

    <context:property-placeholder location="classpath*:spring/easyhome-${spring.profiles.active}.properties" />

    <bean name="authenticationFilter"
        class="org.jasig.cas.client.authentication.AuthenticationFilter">
        <property name="casServerLoginUrl" value="${sso.cas.url.prefix}">property>
        <property name="renew" value="false">property>
        <property name="gateway" value="false">property>
        <property name="serverName" value="${sso.server.name}">property>
    bean>

    <bean name="ticketValidationFilter"
        class="org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter">
        <property name="serverName" value="${sso.server.name}">property>
        <property name="redirectAfterValidation" value="false">property>
        <property name="ticketValidator">
            <bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
                <constructor-arg index="0" value="${sso.cas.url.prefix}" />
            bean>
        property>
    bean>
beans>
View Code

4、在 src\main\java 下新建包 com.xyz.domo.filter ,新建类 FormAuthenticationFilterExt

/*
 * CHONGQING XYZ TECH CO.,LTD
 * Copyright (c) 2015 All Rights Reserved.
 */

/*
 * 修订记录:
 * xiangzy 上午11:09:54 创建
 */
package com.xyz.domo.filter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class FormAuthenticationFilterExt extends AuthenticatingFilter{

    public static final String DEFAULT_ERROR_KEY_ATTRIBUTE_NAME = "shiroLoginFailure";

    public static final String DEFAULT_USERNAME_PARAM = "username";
    public static final String DEFAULT_PASSWORD_PARAM = "password";
    public static final String DEFAULT_REMEMBER_ME_PARAM = "rememberMe";

    private static final Logger log = LoggerFactory.getLogger(FormAuthenticationFilter.class);

    private String usernameParam = DEFAULT_USERNAME_PARAM;
    private String passwordParam = DEFAULT_PASSWORD_PARAM;
    private String rememberMeParam = DEFAULT_REMEMBER_ME_PARAM;

    private String failureKeyAttribute = DEFAULT_ERROR_KEY_ATTRIBUTE_NAME;

    public FormAuthenticationFilterExt() {
        setLoginUrl(DEFAULT_LOGIN_URL);
    }

    @Override
    public void setLoginUrl(String loginUrl) {
        String previous = getLoginUrl();
        if (previous != null) {
            this.appliedPaths.remove(previous);
        }
        super.setLoginUrl(loginUrl);
        if (log.isTraceEnabled()) {
            log.trace("Adding login url to applied paths.");
        }
        this.appliedPaths.put(getLoginUrl(), null);
    }

    public String getUsernameParam() {
        return usernameParam;
    }

    /**
     * Sets the request parameter name to look for when acquiring the username.  Unless overridden by calling this
     * method, the default is username.
     *
     * @param usernameParam the name of the request param to check for acquiring the username.
     */
    public void setUsernameParam(String usernameParam) {
        this.usernameParam = usernameParam;
    }

    public String getPasswordParam() {
        return passwordParam;
    }

    /**
     * Sets the request parameter name to look for when acquiring the password.  Unless overridden by calling this
     * method, the default is password.
     *
     * @param passwordParam the name of the request param to check for acquiring the password.
     */
    public void setPasswordParam(String passwordParam) {
        this.passwordParam = passwordParam;
    }

    public String getRememberMeParam() {
        return rememberMeParam;
    }

    /**
     * Sets the request parameter name to look for when acquiring the rememberMe boolean value.  Unless overridden
     * by calling this method, the default is rememberMe.
     * 

* RememberMe will be true if the parameter value equals any of those supported by * {@link org.apache.shiro.web.util.WebUtils#isTrue(javax.servlet.ServletRequest, String) WebUtils.isTrue(request,value)}, false * otherwise. * * @param rememberMeParam the name of the request param to check for acquiring the rememberMe boolean value. */ public void setRememberMeParam(String rememberMeParam) { this.rememberMeParam = rememberMeParam; } public String getFailureKeyAttribute() { return failureKeyAttribute; } public void setFailureKeyAttribute(String failureKeyAttribute) { this.failureKeyAttribute = failureKeyAttribute; } protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { HttpServletRequest httpServletRequest = (HttpServletRequest)request; String ajaxFlag = httpServletRequest.getHeader("x-requested-with"); if (isLoginRequest(request, response)) { if (isLoginSubmission(request, response)) { if (log.isTraceEnabled()) { log.trace("Login submission detected. Attempting to execute login."); } return executeLogin(request, response); } else { if (log.isTraceEnabled()) { log.trace("Login page view."); } //allow them to see the login page ;) if(null!=ajaxFlag&&"XMLHttpRequest".equals(ajaxFlag)){ log.debug("ajax request must return json update by xzy..."); String returnStr = "{\"recordsFiltered\":0,\"data\":[],\"notLogin\":true,\"recordsTotal\":0}"; response.getWriter().write(returnStr); return false; } return true; } } else { if (log.isTraceEnabled()) { log.trace("Attempting to access a path which requires authentication. Forwarding to the " + "Authentication url [" + getLoginUrl() + "]"); } if(null!=ajaxFlag&&"XMLHttpRequest".equals(ajaxFlag)){ log.debug("ajax request must return json update by xzy..."); String returnStr = "{\"recordsFiltered\":0,\"data\":[],\"notLogin\":true,\"recordsTotal\":0}"; response.getWriter().write(returnStr); }else{ saveRequestAndRedirectToLogin(request, response); } //saveRequestAndRedirectToLogin(request, response); return false; } } /** * This default implementation merely returns true if the request is an HTTP POST, * false otherwise. Can be overridden by subclasses for custom login submission detection behavior. * * @param request the incoming ServletRequest * @param response the outgoing ServletResponse. * @return true if the request is an HTTP POST, false otherwise. */ protected boolean isLoginSubmission(ServletRequest request, ServletResponse response) { return (request instanceof HttpServletRequest) && WebUtils.toHttp(request).getMethod().equalsIgnoreCase(POST_METHOD); } protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) { String username = getUsername(request); String password = getPassword(request); return createToken(username, password, request, response); } protected boolean isRememberMe(ServletRequest request) { return WebUtils.isTrue(request, getRememberMeParam()); } protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception { issueSuccessRedirect(request, response); //we handled the success redirect directly, prevent the chain from continuing: return false; } protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) { setFailureAttribute(request, e); //login failed, let request continue back to the login page: return true; } protected void setFailureAttribute(ServletRequest request, AuthenticationException ae) { String className = ae.getClass().getName(); request.setAttribute(getFailureKeyAttribute(), className); } protected String getUsername(ServletRequest request) { return WebUtils.getCleanParam(request, getUsernameParam()); } protected String getPassword(ServletRequest request) { return WebUtils.getCleanParam(request, getPasswordParam()); } }

View Code

4.1、新建类 SSOLogoutFilter

/*
 * CHONGQING XYZ TECH CO.,LTD
 * Copyright (c) 2015 All Rights Reserved.
 */

/*
 * 修订记录:
 * xiangzy 下午6:11:24 创建
 */
package com.xyz.domo.filter;

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xyz.domo.common.http.WebUtils;
import com.xyz.domo.common.properties.PropertiesUtil;



public class SSOLogoutFilter implements Filter {

    protected final Logger    logger  = LoggerFactory.getLogger(getClass());
    /**
     * @param filterConfig
     * @throws ServletException
     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    /**
     * @param request
     * @param response
     * @param chain
     * @throws IOException
     * @throws ServletException
     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
        try {
            HttpServletRequest httpservletrequest = (HttpServletRequest) request;
            String logoutRequest = httpservletrequest.getParameter("logoutRequest");
            logger.debug("cas post logout logoutRequest parameter value===>"+logoutRequest);
            String logoutFlag = httpservletrequest.getParameter("logoutFlag");
            if(StringUtils.isNotBlank(logoutRequest)&&StringUtils.isBlank(logoutFlag)){
                String url1 = PropertiesUtil.getInstance().getSysPro("server.ip1");
                String url2 = PropertiesUtil.getInstance().getSysPro("server.ip2");
                String currentIp = getIpAddress();
                logger.debug("cas post logout client, currentIp:【{}】, url1:【{}】, url2:【{}】", new Object[]{currentIp, url1, url2});
                if(url1.contains(currentIp)){
                    WebUtils.doPost(url2, getAllParam(httpservletrequest), 30000, 30000);
                }else if(url2.contains(currentIp)){
                    WebUtils.doPost(url1, getAllParam(httpservletrequest), 30000, 30000);
                }
                logger.debug("cas post logout client");
            }
        } catch (Exception e) {
            logger.error("shiro logout error",e);
        }
        chain.doFilter(request, response);
    }

    /**
     * 
     * @see javax.servlet.Filter#destroy()
     */
    @Override
    public void destroy() {
    }
    
    //获取当前IP
    private  String getIpAddress() throws UnknownHostException {   
        InetAddress address = InetAddress.getLocalHost();   
        return address.getHostAddress();   
    }  

    //获取request对象的所有请求参数
    private Map getAllParam(HttpServletRequest request){
        Map map = new HashMap();
        Enumeration paramNames = request.getParameterNames();
        StringBuffer strBuffer = new StringBuffer();
        while (paramNames.hasMoreElements()) {
            String paramName = (String) paramNames.nextElement();

            String[] paramValues = request.getParameterValues(paramName);
            if (paramValues.length == 1) {
                String paramValue = paramValues[0];
                if (paramValue.length() != 0) {
                    strBuffer.append(paramName).append("=").append(paramValue).append(",");
                    map.put(paramName, paramValue);
                }
            }
        }
        map.put("logoutFlag", "yes");
        return map;
    }

}
View Code

5、在 src\main\java 下新建包 com.xyz.domo.controller.realm,新建类 MyCasRealm 用于接收服务端返回的登录信息

/*
 * CHONGQING XYZ TECH CO.,LTD
 * Copyright (c) 2015 All Rights Reserved.
 */

/*
 * 修订记录:
 * Tzw 上午10:02:21 创建
 */
package com.xyz.domo.controller.realm;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.apache.bcel.generic.NEW;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cas.CasAuthenticationException;
import org.apache.shiro.cas.CasRealm;
import org.apache.shiro.cas.CasToken;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.util.StringUtils;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.TicketValidationException;
import org.jasig.cas.client.validation.TicketValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.support.AbstractCacheManager;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xyz.dal.mybatis.model.User;


/**
 * @Filename MyCasRealm.java
 *
 * @Description:
 *
 * @Version 1.0
 *
 * @Author 
 *
 * @Email
 *
 */
public class MyCasRealm extends CasRealm {
    
    private static Logger log = LoggerFactory.getLogger(MyCasRealm.class);
    
    @Autowired
    AbstractCacheManager ehCacheCacheManager;
    
    @SuppressWarnings("unchecked")
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        Subject subject = SecurityUtils.getSubject();
        
        Set permissions = new HashSet();
        List permissionInfo = (List)subject.getSession().getAttribute("permissionInfo");
        if(permissionInfo != null){
            permissions.addAll(permissionInfo);
        }
        
        Set roles = new HashSet();
        List roleInfo = (List)subject.getSession().getAttribute("roleInfo");
        if(roleInfo != null){
            roles.addAll(roleInfo);
        }
        
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setStringPermissions(permissions);
        authorizationInfo.setRoles(roles);
        
        return authorizationInfo;
    }
    
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        CasToken casToken = (CasToken) token;
        if (token == null) {
            return null;
        }
        
        String ticket = (String) casToken.getCredentials();
        if (!StringUtils.hasText(ticket)) {
            return null;
        }
        
        TicketValidator ticketValidator = ensureTicketValidator();
        
        try {
            // contact CAS server to validate service ticket
            Assertion casAssertion = ticketValidator.validate(ticket, getCasService());
            // get principal, user id and attributes
            AttributePrincipal casPrincipal = casAssertion.getPrincipal();
            String userId = casPrincipal.getName();
            log.debug("Validate ticket : {} in CAS server : {} to retrieve user : {}", new Object[] { ticket, getCasServerUrlPrefix(), userId });
            
            Map attributes = casPrincipal.getAttributes();
            Subject subject = SecurityUtils.getSubject();
            
            // 获取用户信息
            String userStr = (String)attributes.get("userInfo");
            List staffInfo = JSON.parseArray(userStr, User.class);
            subject.getSession().setAttribute("staffInfo", staffInfo);
            // 获取权限信息
        /*String permissionInfo = (String)attributes.get("permissionInfo");
            List permissionInfos = JSON.parseArray(permissionInfo, String.class);
            subject.getSession().setAttribute("permissionInfo", permissionInfos);
            // 获取角色信息
            String roleInfo = (String)attributes.get("roleInfo");
            List roleInfos = JSON.parseArray(roleInfo, String.class);
            subject.getSession().setAttribute("roleInfo", roleInfos);*/
            // refresh authentication token (user id + remember me)
            casToken.setUserId(userId);
            String rememberMeAttributeName = getRememberMeAttributeName();
            String rememberMeStringValue = (String) attributes.get(rememberMeAttributeName);
            boolean isRemembered = rememberMeStringValue != null&& Boolean.parseBoolean(rememberMeStringValue);
            if (isRemembered) {
                casToken.setRememberMe(true);
            }
            // create simple authentication info
            List principals = CollectionUtils.asList(userId, attributes);
            PrincipalCollection principalCollection = new SimplePrincipalCollection(principals,getName());
            return new SimpleAuthenticationInfo(principalCollection, ticket);
        } catch (TicketValidationException e) {
            throw new CasAuthenticationException("Unable to validate ticket [" + ticket + "]", e);
        }
    }
    
} 
     
    View Code 
    
   

 源码下载:点击下载

转载于:https://www.cnblogs.com/miskis/p/6393780.html

你可能感兴趣的:(cas 服务端、客服端详细配置)