一、文件jeeplus.properties,添加配置
内容如下:

cas.server.serverurlprefix.url=http://10.10.128.90:7001/cas
cas.project.service=http://10.10.128.90:7002/portal
shiro.service=${cas.project.service}/cas/login
shiro.failureUrl=/webpage/error/error_cas.jsp
cas.server.login.url=${cas.server.serverurlprefix.url}?service=${shiro.service}
cas.server.logout.url=${cas.server.serverurlprefix.url}/logout?service=${cas.project.service}

注意:只有门户在退出时去cas服务注销token,各个子系统在注销时只注销自己的session就可以了

在各个子系统中配置:

cas.server.serverurlprefix.url=http://10.10.128.90:7001/cas
cas.project.service=http://10.10.128.90:7003/zxt
cas.project.service2=http://10.10.128.90:7003/portal
shiro.service=${cas.project.service}/cas/login
shiro.failureUrl=/webpage/error/error_cas.jsp
cas.server.login.url=${cas.server.serverurlprefix.url}?service=${shiro.service}
cas.server.logout.url=${cas.project.service2}/logout

二、修改文件 spring-context-shiro.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsdhttp://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.0.xsd"default-lazy-init="true"><description>Shiro Configuration</description><!-- 加载配置属性文件 --><context:property-placeholder ignore-unresolvable="true" location="classpath:/config/jeeplus.properties" /><!-- Shiro权限过滤过滤器定义 --><bean name="shiroFilterChainDefinitions" class="java.lang.String"><constructor-arg><value>/static/** = anon/userfiles/** = anon${adminPath}/sys/user/infoCareStatus = anon${adminPath}/sys/user/validateLoginName = anon${adminPath}/sys/user/validateMobile = anon${adminPath}/sys/user/validateMobileExist = anon${adminPath}/sys/user/resetPassword = anon${adminPath}/sys/register = anon${adminPath}/sys/register/registerUser = anon${adminPath}/sys/register/getRegisterCode = anon${adminPath}/sys/register/validateMobileCode = anon${adminPath}/soft/sysVersion/getAndroidVer = anon${adminPath}/soft/sysVersion/getIosVer = anon/cas/login = casFilter${adminPath}/login = user${adminPath}/logout = logoutFilter${adminPath}/** = user/act/rest/service/editor/** = perms[act:model:edit]/act/rest/service/model/** = perms[act:model:edit]/act/rest/service/** = user/ReportServer/** = user</value></constructor-arg></bean><!-- 安全认证过滤器 --><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><property name="securityManager" ref="securityManager" /><property name="loginUrl" value="${cas.server.login.url}" /><property name="filters"><map><entry key="casFilter" value-ref="casFilter" /><entry key="logoutFilter" value-ref="logoutFilter" /></map></property><property name="filterChainDefinitions"><ref bean="shiroFilterChainDefinitions"/></property></bean><!-- CAS认证过滤器 --><bean id="casFilter" class="com.jeeplus.common.security.shiro.UserCasFilter"><property name="failureUrl" value="${shiro.failureUrl}"/></bean><bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter"><property name="redirectUrl" value="${cas.server.logout.url}" /></bean><bean id="casRealm" class="com.jeeplus.common.security.shiro.UserRealm"><!-- 认证通过后的默认角色 --><property name="defaultRoles" value="ROLE_USER" /><!-- cas服务端地址前缀 --><property name="casServerUrlPrefix" value="${cas.server.serverurlprefix.url}" /><!-- 应用服务地址,用来接收cas服务端票据 --><property name="casService" value="${shiro.service}" /></bean><!-- 定义Shiro安全管理配置 --><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="realm" ref="casRealm" /><property name="sessionManager" ref="sessionManager" /><property name="cacheManager" ref="shiroCacheManager" /></bean><!-- 自定义会话管理配置 --><bean id="sessionManager" class="com.jeeplus.common.security.shiro.session.SessionManager"><property name="sessionDAO" ref="sessionDAO"/><!-- 会话超时时间,单位:毫秒  --><property name="globalSessionTimeout" value="${session.sessionTimeout}"/><!-- 定时清理失效会话, 清理用户直接关闭浏览器造成的孤立会话   --><property name="sessionValidationInterval" value="${session.sessionTimeoutClean}"/><!--          <property name="sessionValidationSchedulerEnabled" value="false"/> --><property name="sessionValidationSchedulerEnabled" value="true"/><property name="sessionIdCookie" ref="sessionIdCookie"/><property name="sessionIdCookieEnabled" value="true"/></bean><!-- 指定本系统SESSIONID, 默认为: JSESSIONID 问题: 与SERVLET容器名冲突, 如JETTY, TOMCAT 等默认JSESSIONID,当跳出SHIRO SERVLET时如ERROR-PAGE容器会为JSESSIONID重新分配值导致登录会话丢失! --><bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"><constructor-arg name="name" value="jeeplus.session.id"/></bean><!-- 自定义Session存储容器 --><bean id="sessionDAO" class="com.jeeplus.common.security.shiro.session.CacheSessionDAO"><property name="sessionIdGenerator" ref="idGen" /><property name="activeSessionsCacheName" value="activeSessionsCache" /><property name="cacheManager" ref="shiroCacheManager" /></bean><!-- 定义授权缓存管理器 --><bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"><property name="cacheManager" ref="cacheManager" /></bean><!-- 保证实现了Shiro内部lifecycle函数的bean执行 --><bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/><!-- AOP式方法级权限检查  --><bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"><property name="proxyTargetClass" value="true" /></bean><bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"><property name="securityManager" ref="securityManager"/></bean></beans>

三、新建文件UserRealm.java

package com.jeeplus.common.security.shiro;import com.jeeplus.common.config.Global;
import com.jeeplus.common.utils.Encodes;
import com.jeeplus.common.utils.SpringContextHolder;
import com.jeeplus.common.utils.StringUtils;
import com.jeeplus.common.web.Servlets;
import com.jeeplus.modules.sys.entity.Menu;
import com.jeeplus.modules.sys.entity.Role;
import com.jeeplus.modules.sys.entity.User;
import com.jeeplus.modules.sys.security.SystemAuthorizingRealm;
import com.jeeplus.modules.sys.service.SystemService;
import com.jeeplus.modules.sys.utils.LogUtils;
import com.jeeplus.modules.sys.utils.UserUtils;
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.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.Permission;
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.ByteSource;
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.stereotype.Service;import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;/*** 系统安全认证实现类* @author jeeplus* @version 2017-7-5*/
@Service
//@DependsOn({"userMapper","roleMapper","menuMapper"})
public class UserRealm extends CasRealm {private Logger logger = LoggerFactory.getLogger(getClass());private SystemService systemService;@AutowiredHttpServletRequest request;/*** 认证回调函数, 登录时调用*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {CasToken casToken = (CasToken)token;if (token == null) {return null;} else {String ticket = (String) casToken.getCredentials();if (!org.apache.shiro.util.StringUtils.hasText(ticket)) {return null;} else {//ticket检验器TicketValidator ticketValidator = ensureTicketValidator();int activeSessionSize = getSystemService().getSessionDao().getActiveSessions(false).size();try {String casservice=getCasService();// 去CAS服务端中验证ticket的合法性Assertion casAssertion = ticketValidator.validate(ticket, casservice);// 从CAS服务端中获取相关属性,包括用户名、是否设置RememberMe等AttributePrincipal casPrincipal = casAssertion.getPrincipal();String userId = casPrincipal.getName();if (logger.isDebugEnabled()){logger.debug("login submit, active session size: {}, username: {}", activeSessionSize, userId);}// 校验用户名密码User user = getSystemService().getUserByLoginName(userId);if (user != null) {if (Global.NO.equals(user.getLoginFlag())){throw new AuthenticationException("msg:该已帐号禁止登录.");}byte[] salt = Encodes.decodeHex(user.getPassword().substring(0,16));SystemAuthorizingRealm.Principal principals=new SystemAuthorizingRealm.Principal(user,false);String name=getName();ByteSource bytesource= ByteSource.Util.bytes(userId);return new SimpleAuthenticationInfo(principals, ticket,bytesource , name);} else {return null;}} catch (TicketValidationException e) {throw new CasAuthenticationException("Unable to validate ticket [" + ticket + "]", e);}}}}/*** 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {Object _principal= principals.getPrimaryPrincipal();String username = getFieldValueByName("loginName",_principal);User user = getSystemService().getUserByLoginName(username);if (user != null) {SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();List<Menu> list = UserUtils.getMenuList();for (Menu menu : list){if (StringUtils.isNotBlank(menu.getPermission())){// 添加基于Permission的权限信息for (String permission : StringUtils.split(menu.getPermission(),",")){info.addStringPermission(permission);}}}// 添加用户权限info.addStringPermission("user");// 添加用户角色信息for (Role role : user.getRoleList()){info.addRole(role.getEnname());}// 更新登录IP和时间getSystemService().updateUserLoginInfo(user);// 记录登录日志LogUtils.saveLog(Servlets.getRequest(), "系统登录");return info;} else {return null;}}private String getFieldValueByName(String fieldName,  Object o) {try {String firstLetter = fieldName.substring(0, 1).toUpperCase();String getter = "get" + firstLetter + fieldName.substring(1);Method method = o.getClass().getMethod(getter, new Class[] {});Object value = method.invoke(o, new Object[] {});return (String)value;} catch (Exception e) {return null;}}@Overrideprotected void checkPermission(Permission permission, AuthorizationInfo info) {authorizationValidate(permission);super.checkPermission(permission, info);}@Overrideprotected boolean[] isPermitted(List<Permission> permissions, AuthorizationInfo info) {if (permissions != null && !permissions.isEmpty()) {for (Permission permission : permissions) {authorizationValidate(permission);}}return super.isPermitted(permissions, info);}@Overridepublic boolean isPermitted(PrincipalCollection principals, Permission permission) {authorizationValidate(permission);return super.isPermitted(principals, permission);}@Overrideprotected boolean isPermittedAll(Collection<Permission> permissions, AuthorizationInfo info) {if (permissions != null && !permissions.isEmpty()) {for (Permission permission : permissions) {authorizationValidate(permission);}}return super.isPermittedAll(permissions, info);}/*** 授权验证方法* @param permission*/private void authorizationValidate(Permission permission){// 模块授权预留接口}/*** 设定密码校验的Hash算法与迭代次数*///@PostConstructpublic void initCredentialsMatcher() {HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(SystemService.HASH_ALGORITHM);matcher.setHashIterations(SystemService.HASH_INTERATIONS);setCredentialsMatcher(matcher);}//    /**
//   * 清空用户关联权限认证,待下次使用时重新加载
//   */public void clearCachedAuthorizationInfo(Principal principal) {SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());clearCachedAuthorizationInfo(principals);}/*** 清空所有关联认证* @Deprecated 不需要清空,授权缓存保存到session中*/@Deprecatedpublic void clearAllCachedAuthorizationInfo() {
//      Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
//      if (cache != null) {
//          for (Object key : cache.keys()) {
//              cache.remove(key);
//          }
//      }}/*** 获取系统业务对象*/public SystemService getSystemService() {if (systemService == null){systemService = SpringContextHolder.getBean(SystemService.class);}return systemService;}/*** 授权用户信息*/public static class Principal implements Serializable {private static final long serialVersionUID = 1L;private String id; // 编号private String loginName; // 登录名private String name; // 姓名private boolean mobileLogin; // 是否手机登录//     private Map<String, Object> cacheMap;public Principal(User user, boolean mobileLogin) {this.id = user.getId();this.loginName = user.getLoginName();this.name = user.getName();this.mobileLogin = mobileLogin;}public String getId() {return id;}public String getLoginName() {return loginName;}public String getName() {return name;}public boolean isMobileLogin() {return mobileLogin;}/*** 获取SESSIONID*/public String getSessionid() {try{return (String) UserUtils.getSession().getId();}catch (Exception e) {return "";}}@Overridepublic String toString() {return id;}}
}

四、单点登录认证异常

创建单点登录认证类UserCasFilter

package com.jeeplus.common.security.shiro;import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.cas.CasFilter;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.FileNotFoundException;
import java.io.IOException;public class UserCasFilter extends CasFilter {private String failureUrl;private static Logger logger = LoggerFactory.getLogger(CasFilter.class);@Overrideprotected boolean onLoginFailure(AuthenticationToken token, AuthenticationException ae, ServletRequest request, ServletResponse response) {try {request.setAttribute("exception", ae);request.getRequestDispatcher(this.failureUrl).forward(request, response);} catch (Exception e) {e.printStackTrace();logger.error("权限认证失败", e);}return false;}public void setFailureUrl(String failureUrl) {this.failureUrl = failureUrl;}
}

创建error/error_cas.jsp文件

<%response.setStatus(500);// 获取异常类Throwable ex = Exceptions.getThrowable(request);if (ex != null) {LoggerFactory.getLogger("500.jsp").error(ex.getMessage(), ex);}// 编译错误信息StringBuilder sb = new StringBuilder("错误信息:\n");if (ex != null) {sb.append(Exceptions.getStackTraceAsString(ex));} else {sb.append("未知错误.\n\n");}// 如果是异步请求或是手机端,则直接返回信息if (Servlets.isAjaxRequest(request)) {out.print(sb);}// 输出异常信息页面else {
%>
<%@page import="org.slf4j.Logger,org.slf4j.LoggerFactory" %>
<%@page import="com.jeeplus.common.web.Servlets" %>
<%@page import="com.jeeplus.common.utils.Exceptions" %>
<%@page import="com.jeeplus.common.utils.StringUtils" %>
<%@page contentType="text/html;charset=UTF-8" isErrorPage="true" %>
<%@include file="/webpage/include/taglib.jsp" %>
<!DOCTYPE html>
<html>
<head><title>权限认证失败</title><link rel="stylesheet" href="${ctxStatic}/common/css/mainStyle.css"/><%@include file="/webpage/include/head.jsp" %><style type="text/css">.errorBox {position: absolute;top: 50%;left: 50%;width: 600px;height: 300px;margin-left: -300px;margin-top: -200px;}.errorBox .errorImg {width: 100%;text-align: center;}.errorBox .errorTxt1 {width: 100%;padding-top: 20px;text-align: center;color: #333;font-size: 18px;line-height: 1;}.errorBox .errorTxt2 {width: 100%;padding-top: 10px;text-align: center;color: #666;font-size: 14px;line-height: 1}.errorBox .authorizeErrorTxt {width: 100%;margin-top: -35px;text-align: center;color: #666;font-size: 18px;line-height: 1;}.errorBox .authorizeErrorBtn {width: 100%;margin-top: 15px;text-align: center;}.errorBox .authorizeErrorBtn a {display: block;padding: 5px 15px;border-radius: 15px;border: 2px solid #00bd9c;color: #333;width: 116px;font-size: 14px;margin: 30px auto 0;}.errorBox .unknownErrorTxt {width: 100%;padding-top: 20px;text-align: center;color: #333;font-size: 18px;line-height: 1;}.errorBox .unknownErrorBtn {width: 100%;text-align: center;}.errorBox .unknownErrorBtn a {display: inline-block;padding: 5px 15px;border-radius: 15px;border: 2px solid #00bd9c;color: #333;width: 116px;font-size: 14px;margin: 30px auto 0;}</style><script type="text/javascript">function showErrorMsg() {var temp = $(".errorMessage").clone();temp.removeClass('hide');top.layer.open({type: 1,skin: 'layerui-layer-rim',title: '错误详细信息',area: ['1000px', '600px'],content: temp.html(),btn: ['关闭']});}</script>
</head>
<body>
<div class="errorBox" style="height: 500px;margin-top:-300px;"><div class="errorImg"><img src="${ctxWebpage}/static/common/img/unknownError.png"></div><div class="container-fluid"><div class="unknownErrorTxt">权限认证失败</div><div class="unknownErrorBtn">错误信息:<%=ex == null ? "权限认证失败." : StringUtils.toHtml(ex.getMessage())%> <br/> <br/>请点击“查看详细信息”按钮,将详细错误信息发送给系统管理员,谢谢!<br/> <br/><a href="javascript:" onclick="window.close();" class="btn">关闭当前页</a> &nbsp;<a href="javascript:" onclick="showErrorMsg()" class="btn">查看详细信息</a></div><div class="errorMessage hide"><%=StringUtils.toHtml(sb.toString())%> <br/></div><script>try {top.$.jBox.closeTip();} catch (e) {}</script></div>
</div>
</body>
</html>
<%}out = pageContext.pushBody();
%>

五、未能够识别出目标 ***;票根

修改cas服务端相关配置文件: cas.properties

st.timeToKillInSeconds=10

原因,默认值时间是1.8秒,当登录成功,携带ST返回客户端,客户端带着server和ST去服务器验证,但此时服务器端的ST已经失效。

JEEPLUS集成CAS的方案相关推荐

  1. web工程中集成cas单点登录

    背景 cas的服务端已经搭建成功,现在需要在web项目中集成cas client.我们项目使用spring 1.在pom中配置 <!--cas单点登录 --><dependency& ...

  2. Chrome浏览器上集成IE内核方案

    Chrome浏览器上集成IE内核方案 1. 架构图 双核功能的基本思路是,在chrome原有的render 管理的基础上,添加trident内核对象并在切换时将两个渲染的内核数据进行同步,进而将内核网 ...

  3. Jeesite单点登录集成Cas另加自定义登录验证

    Jeesite单点登录集成Cas另加自定义登录验证 JeeSite是基于多个优秀的开源项目,高度整合封装而成的高效,高性能,强安全性的 开源 Java EE快速开发平台. Cas主要是用来解决多应用之 ...

  4. Ambari 集成LDAP技术方案

    Ambari 集成LDAP技术方案 一.集成准备 1.TCL安装部署 wget http://nchc.dl.sourceforge.net/sourceforge/tcl/tcl8.4.11-src ...

  5. springmvc集成cas,并解决前后端分离情况

    2019独角兽企业重金招聘Python工程师标准>>> 1.最近项目需要集成已经存在的cas系统. 但是目前已集成的系统都是jsp.而我们项目是前后端分离开发(伪),没有分开部署. ...

  6. 多服务集成CAS实现单点登录

    简要概述实现步骤(思路): 1.创建web应用 2.集成CAS(使用CAS服务端内配置账户密码进行登录验证) 2.1导入jar包 2.2配置web.xml文件(拦截跳转验证以及验证结束返回) 3.配置 ...

  7. CAS学习笔记五:SpringBoot自动/手动配置方式集成CAS单点登出

    本文目标 基于SpringBoot + Maven 分别使用自动配置与手动配置过滤器方式实现CAS客户端登出及单点登出. 本文基于<CAS学习笔记三:SpringBoot自动/手动配置方式集成C ...

  8. SSO、单点登录、集成 CAS、OAuth2

    SSO.单点登录.集成 CAS.OAuth2 JeeSite 已经默认集成了两种单点登录方式(Single Sign On): 1.SSO(简单登录)接口,实现快速登录系统. 2.与 Apereo C ...

  9. python学习04--django集成CAS客户端

    python学习04--django集成CAS客户端 前言 一.CAS客户端 1.新建一个Django项目,前面已讲, 2.安装依赖 3.配置Django_cas_ng,在settings文件中 4. ...

最新文章

  1. 根据刚体上若干个点的加速度确定任意点的加速度的方法
  2. OriginPro 2021 for win 科学绘图软件最新版 中英文 完美稳定附下载安装使用教程
  3. 交大计算机基础知识第一次作业,上海交大计算机第一次作业
  4. 绕过waf mysql爆库_iwebsec刷题记录-SQL注入漏洞
  5. Android 帧动画 xml 方式实现
  6. ES2005 js =
  7. 和机器学习和计算机视觉相关的数学(转载)
  8. [原创]Linux下网络性能测试Netperf工具介绍及安装
  9. ajaxSubmit
  10. 新浪微博产品分析报告
  11. 关于JSZIP压缩图片打包下载的一些用法
  12. Jmeter使用HTTP代理服务器无法打开网页问题的解决方法
  13. 华为:三层交换机 命令示例
  14. Ubuntu快速下载电驴ed2k文件
  15. List<?>和list的区别
  16. Qmail的配置文件详解
  17. 一文搞懂高速CAN收发器TJA1145
  18. java 线程亲缘性_线程的调度、优先级和亲缘性
  19. TCP面向连接中的“连接”究竟是什么,可靠与不可靠
  20. Kafka系列 - 10 Kafka副本|分区副本分配|手动调整分区副本|Leader Partition 负载平衡|增加副本因子

热门文章

  1. 各个tts的下载地址及介绍
  2. The driver has not received any packets from the server,java.net.ConnectException: Connection refuse
  3. 使用Clang作为编译器 —— Clang 语言扩展
  4. TCP协议中的PSH和URG标志位
  5. 下载搜狐小说-软件介绍
  6. tensorflow+keras安装
  7. Python数据分析绘图库,pyecharts绘制各类地图
  8. 明天就是情人节了,大家都打算什么礼物给女友
  9. 如何成为一名合格的网络安全工程师?需要掌握那些能力?
  10. 【服装设计作品】黑白灰中国风礼服,也能惊艳全场!