由於現有系統外部接入須要,須要支持三方單點登陸。因爲系統自己已是微服務架構,由多個業務獨立的子系統組成,因此有本身的用戶認證微服務(不是cas,咱們基礎設施已經夠多了,如今能不增長就不增長)。可是由於客戶和其餘接入(公有云網絡)緣由,沒法經過token+redis實現,因此還須要支持外部的cas。html
現有認證系統採用shiro實現,業務子系統採用shiro+token假登陸實現。如今要支持經過配置設置系統自身的認證子系統是否啓用三方cas登陸。這樣不管是使用本身的認證明現、仍是三方CAS,總體流程就徹底同樣。java
從cas 4開始,官方就已經再也不提供release war,轉而須要自行下載源碼打包,網上不少,這裏再也不闡述(下載依賴有點慢)。4.x以及以前的war能夠從https://mvnrepository.com/artifact/org.jasig.cas/cas-server-webapp下載。下載後,解壓到tomcat webapp目錄:git
啓動:github
修改下列配置:web
去除https認證:redis
在tomcat\webapps\cas\WEB-INF\deployerConfigContext.xml文件 的p:httpClient-ref="httpClient"後面添加p:requireSecure="false" 把tomcat\webapps\cas\WEB-INF\spring-configuration的 ticketGrantingTicketCookieGenerator.xml文件裏面把p:cookieSecure="true"改成false; p:cookieMaxAge="-1"改成3600(-1是不保存cookie,3600秒是一個小時,保存登陸信息) 把tomcat\webapps\cas\WEB-INF\spring-configuration的 warnCookieGenerator.xml的p:cookieSecure="true"改成false p:cookieMaxAge="-1"改成3600
配置單點登出: spring
將tomcat\webapps\cas\WEB-INF\cas-servlet.xml中${cas.logout.followServiceRedirects:false}括號裏的值改成trueapi
能夠配置簡單測試認證(去掉<bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" />註釋)或基於數據源認證(能夠參考https://www.cnblogs.com/wlwl/p/10056067.html)。tomcat
庫依賴:服務器
<dependency> <groupId>net.unicon.cas</groupId> <artifactId>cas-client-autoconfig-support</artifactId> <version>1.5.0-GA</version> </dependency> <dependency> <groupId>org.jasig.cas.client</groupId> <artifactId>cas-client-core</artifactId> <version>3.2.1</version> <exclusions> <exclusion> <artifactId>servlet-api</artifactId> <groupId>javax.servlet</groupId> </exclusion> </exclusions> </dependency>
application.properties中加上下列配置:
cas.server-url-prefix=http://localhost:8080/cas
cas.server-login-url=http://localhost:8080/cas/login
cas.client-host-url=http://localhost:18080/
cas.use-session=true
cas.validation-type=cas
casClientLogoutUrl=http://localhost:8080/cas/logout?service=http://localhost:18080/tabase/logout.html
import net.unicon.cas.client.configuration.EnableCasClient; @EnableCasClient //啓用cas client @CloudApplication public class ConsumerStarter { public static void main(String[] args) { CloudBootstrap.run(ConsumerStarter.class, args); } } package com.hs; import java.util.HashMap; import java.util.Map; import org.jasig.cas.client.authentication.AuthenticationFilter; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class CASAutoConfig { @Value("${cas.server-url-prefix}") private String serverUrlPrefix; @Value("${cas.server-login-url}") private String serverLoginUrl; @Value("${cas.client-host-url}") private String clientHostUrl; /** * 受權過濾器 * @return */ @Bean public FilterRegistrationBean filterAuthenticationRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new AuthenticationFilter()); // 設定匹配的路徑 registration.addUrlPatterns("/*"); Map<String,String> initParameters = new HashMap<String, String>(); initParameters.put("casServerLoginUrl", serverUrlPrefix); initParameters.put("serverName", clientHostUrl); //忽略的url,"|"分隔多個url initParameters.put("ignorePattern", "/logout/success|/index"); registration.setInitParameters(initParameters); // 設定加載的順序 registration.setOrder(1); return registration; } }
cas登陸成功後,會給應用返回ticket,其中包含了用戶名。此時應用主頁會被shiro過濾器UserFilter攔截,在其中能夠判斷HttpServletRequest上是否有ticket的用戶名,有、且爲有效用戶名,就能夠用該用戶名模擬登陸了。這樣整個shiro認證流程幾乎沒有變化,也不須要修改FormAuthenticationFilter。
cas在2.x和3.x版本獲取用戶名不同,這一點須要注意。
2.x版本client獲取CAS傳遞過來的用戶名的方法:
// 如下三者均可以 session.getAttribute(CASFilter.CAS_FILTER_USER); session.getAttribute("edu.yale.its.tp.cas.client.filter.user"); CASFilterRequestWrapper reqWrapper=new CASFilterRequestWrapper(request); reqWrapper.getRemoteUser());
3.x版本client獲取CAS傳遞過來的用戶名的方法:
HttpServletRequest request = ServletActionContext.getRequest(); AttributePrincipal principal = (AttributePrincipal)request.getUserPrincipal(); String username = principal.getName(); Long orgnId = Long.parseLong(principal.getAttributes().get("orgnId").toString());
拿到後,就能夠模擬登錄了。
boolean isAllowed = super.isAccessAllowed(request, response, mappedValue); // if (isAllowed) { } else if (Boolean.valueOf(BaseConfig.getConfig("ta.casEnable","false"))) { AttributePrincipal principal = (AttributePrincipal)((HttpServletRequest) request).getUserPrincipal(); String username = principal.getName(); Subject subject = getSubject(request, response); AuthenticationToken token = new UsernamePasswordToken(); ((UsernamePasswordToken) token).setUsername(username); ((UsernamePasswordToken) token).setPassword(new char[] {'1'}); subject.login(token); isAllowed = super.isAccessAllowed(request, response, mappedValue); }
在shiro的logoutFilter中調用session.invalidate()便可。而後返回casClientLogoutUrl配置的地址退出cas便可。
/** * CAS添加開始 */ if (StringUtils.isNotBlank(BaseConfig.getConfig("casClientLogoutUrl"))) { ((HttpServletRequest)request).getSession().invalidate(); redirectUrl = BaseConfig.getConfig("casClientLogoutUrl"); } // CAS添加結束 return redirectUrl;
此致,就完整的實現了cas+shiro模擬登陸。
CAS ticket過時策略,參考:https://www.cnblogs.com/gao241/p/3367869.html
CAS流程介紹,參考:https://www.cnblogs.com/xiatian0721/p/8136305.html
CAS官方架構參考:https://apereo.github.io/cas/5.3.x/planning/Architecture.html