关于JEEPLUS集成CAS的方案。

分享 未结 精帖 1 912
极限
极限 VIP3 2019-03-21 16:30:34
收藏
三个文件 一、新建文件 casclient.properties 内容如下: [pre] #SSO接入配置 #\u5355\u70b9\u767b\u5f55CAS\u8bbe\u7f6e cas.server.url=http://XXXXXXXXX/casserver?service=http://localhost:8080/cas/caslogin cas.server.serverurlprefix.url=http://XXXXXXXXX/casserver cas.project.url=http://127.0.0.1:8080/jeeplus cas.project.fail.url=/cas/casfail cas.project.logout.url=http://XXXXXXXXX/casserver/logout?service=http://localhost:8080/a/caslogout cas.project.service.url=http://localhost:8080/cas/caslogin #SSO接入配置 [/pre] 二、修改文件 spring-context-shiro.xml [pre] <?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.xsd http://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:/properties/jeeplus.properties" /> <context:property-placeholder ignore-unresolvable="true" location="classpath:/properties/casclient.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/caslogin = cas /cas/casfail=anon ${adminPath}/login = authc ${adminPath}/logout = anon ${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.url}?service=${cas.project.url}${adminPath}/cas" /> --> <property name="loginUrl" value="${cas.server.url}" /> <!--<property name="successUrl" value="${adminPath}?login" />--> <property name="unauthorizedUrl" value="${cas.project.fail.url}" /> <property name="filters"> <map> <entry key="cas" value-ref="casFilter"/> <entry key="authc" value-ref="formAuthenticationFilter"/> </map> </property> <property name="filterChainDefinitions"> <ref bean="shiroFilterChainDefinitions"/> </property> </bean> <!-- CAS认证过滤器 --> <bean id="casFilter" class="org.apache.shiro.cas.CasFilter"> <property name="failureUrl" value="${cas.project.fail.url}"/> </bean> <bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter"> <property name="redirectUrl" value="${cas.project.logout.url}" /> </bean> <bean id="casRealm" class="com.jeeplus.modules.UserRealm"> <!-- 认证通过后的默认角色 --> <property name="defaultRoles" value="ROLE_USER" /> <!-- cas服务端地址前缀 --> <property name="casServerUrlPrefix" value="${cas.server.serverurlprefix.url}" /> <!-- 应用服务地址,用来接收cas服务端票据 --> <property name="casService" value="${cas.project.service.url}" /> </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.core.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.core.security.shiro.session.CacheSessionDAO"> <property name="sessionIdGenerator" ref="idGen" /> <property name="activeSessionsCacheName" value="activeSessionsCache" /> <property name="cacheManager" ref="shiroCacheManager" /> </bean> <!-- 定义授权缓存管理器 --> <!-- <bean id="shiroCacheManager" class="com.jeeplus.core.security.shiro.cache.SessionCacheManager" /> --> <bean id="shiroCacheManager" class="org.nutz.j2cache.shiro.J2CacheManager"> </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> [/pre] 三、新建文件UserRealm.java [pre] /** * 系统安全认证实现类 * @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; @Autowired HttpServletRequest request; /** * 认证回调函数, 登录时调用 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) { CasToken casToken = (CasToken) token; Object credentials=casToken.getCredentials(); String ticket = (String)credentials ; //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); } } /** * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用 */ @Override protected 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; } } @Override protected void checkPermission(Permission permission, AuthorizationInfo info) { authorizationValidate(permission); super.checkPermission(permission, info); } @Override protected boolean[] isPermitted(List<Permission> permissions, AuthorizationInfo info) { if (permissions != null && !permissions.isEmpty()) { for (Permission permission : permissions) { authorizationValidate(permission); } } return super.isPermitted(permissions, info); } @Override public boolean isPermitted(PrincipalCollection principals, Permission permission) { authorizationValidate(permission); return super.isPermitted(principals, permission); } @Override protected 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算法与迭代次数 */ //@PostConstruct public 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中 */ @Deprecated public 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 ""; } } @Override public String toString() { return id; } } } [/pre] 目录结构如下: img[/userfiles/fly/49c6a6c05934412f816c7be102daa005/files/1553156997460.] 里面部份代码没有做修改,自己拿到可以修改。
回帖
  • 2019-03-26 10:17:18
    请问 cas 在登录的时候 要传输什么属性 或者登录的 url是什么 小白求教
    0 回复