什么時候會用到代理proxy模式?
舉一個例子:有兩個應用App1和App2,它們都是受Cas服務器保護的,即請求它們時都需要通過Cas 服務器的認證。現在需要在App1中通過Http請求訪問App2,顯然該請求將會被App2配置的Cas的AuthenticationFilter攔截並轉向Cas 服務器,Cas 服務器將引導用戶進行登錄認證,這樣我們也就訪問不到App2的資源了。針對這種應用場景,Cas也提供了Cas Proxy 輕松的解決了這個問題。
cas server 版本4.1.3
cas clietn版本4.0.0
cas搭建參考:http://www.cnblogs.com/l412382979/p/8818765.html
cas proxy配置參考地址:http://elim.iteye.com/blog/2270446
cas server配置deployerConfigContext.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- 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. --> <!-- | deployerConfigContext.xml centralizes into one file some of the declarative configuration that | all CAS deployers will need to modify. | | This file declares some of the Spring-managed JavaBeans that make up a CAS deployment. | The beans declared in this file are instantiated at context initialization time by the Spring | ContextLoaderListener declared in web.xml. It finds this file because this | file is among those declared in the context parameter "contextConfigLocation". | | By far the most common change you will need to make in this file is to change the last bean | declaration to replace the default authentication handler with | one implementing your approach for authenticating usernames and passwords. +--> <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" 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"> <!-- | The authentication manager defines security policy for authentication by specifying at a minimum | the authentication handlers that will be used to authenticate credential. While the AuthenticationManager | interface supports plugging in another implementation, the default PolicyBasedAuthenticationManager should | be sufficient in most cases. +--> <bean id="authenticationManager" class="org.jasig.cas.authentication.PolicyBasedAuthenticationManager"> <constructor-arg> <map> <!-- | IMPORTANT | Every handler requires a unique name. | If more than one instance of the same handler class is configured, you must explicitly | set its name to something other than its default name (typically the simple class name). --> <entry key-ref="proxyAuthenticationHandler" value-ref="proxyPrincipalResolver" /> <entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" /> <!-- key-ref指定自己的本地數據庫訪問 --> <entry key-ref="dbAuthHandler" value-ref="primaryPrincipalResolver"/> </map> </constructor-arg> <!-- Uncomment the metadata populator to capture the password. <property name="authenticationMetaDataPopulators"> <util:list> <bean class="org.jasig.cas.authentication.CacheCredentialsMetaDataPopulator"/> </util:list> </property> --> <!-- | Defines the security policy around authentication. Some alternative policies that ship with CAS: | | * NotPreventedAuthenticationPolicy - all credential must either pass or fail authentication | * AllAuthenticationPolicy - all presented credential must be authenticated successfully | * RequiredHandlerAuthenticationPolicy - specifies a handler that must authenticate its credential to pass --> <property name="authenticationPolicy"> <bean class="org.jasig.cas.authentication.AnyAuthenticationPolicy" /> </property> </bean> <!-- Required for proxy ticket mechanism. --> <bean id="proxyAuthenticationHandler" class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler" p:httpClient-ref="supportsTrustStoreSslSocketFactoryHttpClient" p:requireSecure="false"/> <!-- | TODO: Replace this component with one suitable for your enviroment. | | This component provides authentication for the kind of credential used in your environment. In most cases | credential is a username/password pair that lives in a system of record like an LDAP directory. | The most common authentication handler beans: | | * org.jasig.cas.authentication.LdapAuthenticationHandler | * org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler | * org.jasig.cas.adaptors.x509.authentication.handler.support.X509CredentialsAuthenticationHandler | * org.jasig.cas.support.spnego.authentication.handler.support.JCIFSSpnegoAuthenticationHandler --> <bean id="primaryAuthenticationHandler" class="org.jasig.cas.authentication.AcceptUsersAuthenticationHandler"> <property name="users"> <map> <entry key="casuser" value="Mellon"/> </map> </property> </bean> <!-- Required for proxy ticket mechanism --> <bean id="proxyPrincipalResolver" class="org.jasig.cas.authentication.principal.BasicPrincipalResolver" /> <!-- | Resolves a principal from a credential using an attribute repository that is configured to resolve | against a deployer-specific store (e.g. LDAP). --> <bean id="primaryPrincipalResolver" class="org.jasig.cas.authentication.principal.PersonDirectoryPrincipalResolver" p:principalFactory-ref="principalFactory" p:attributeRepository-ref="attributeRepository" /> <!-- Bean that defines the attributes that a service may return. This example uses the Stub/Mock version. A real implementation may go against a database or LDAP server. The id should remain "attributeRepository" though. +--> <bean id="attributeRepository" class="org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao"> <constructor-arg index="0" ref="dataSource" /> <constructor-arg index="1" value="select ID_ as id,PASSWORD_ as pwd from USER_TABLE where {0}" /> <property name="queryAttributeMapping"> <map> <!-- 這里的key需寫username和登錄頁面一致,value對應數據庫用戶名字段 select ID_ as id from USER_TABLE where USERNAME_=#username# --> <entry key="username" value="USERNAME_"/> </map> </property> <property name="resultAttributeMapping"> <map> <!-- key為對應的數據庫字段名稱,value為提供給客戶端獲取的屬性名字,系統會自動填充值 --> <entry key="id" value="id"/> <entry key="pwd" value="pwd"/> </map> </property> </bean> <bean id="serviceRegistryDao" class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl" p:registeredServices-ref="registeredServicesList" /> <util:list id="registeredServicesList"> <bean class="org.jasig.cas.services.RegexRegisteredService" p:id="1" p:name="HTTPS and IMAPS services on example.com" p:serviceId="^(https?|imaps?|http?)://.*" p:evaluationOrder="0" > <!-- 基於正則表達式匹配代理端,以下這行不加的話代理端會被cas server拒絕 --> <property name="proxyPolicy"> <bean class="org.jasig.cas.services.RegexMatchingRegisteredServiceProxyPolicy" c:pgtUrlPattern="^https?://.*" /> </property> </bean> </util:list> <bean id="auditTrailManager" class="org.jasig.inspektr.audit.support.Slf4jLoggingAuditTrailManager" /> <bean id="healthCheckMonitor" class="org.jasig.cas.monitor.HealthCheckMonitor" p:monitors-ref="monitorsList" /> <util:list id="monitorsList"> <bean class="org.jasig.cas.monitor.MemoryMonitor" p:freeMemoryWarnThreshold="10" /> <!-- NOTE The following ticket registries support SessionMonitor: * DefaultTicketRegistry * JpaTicketRegistry Remove this monitor if you use an unsupported registry. --> <bean class="org.jasig.cas.monitor.SessionMonitor" p:ticketRegistry-ref="ticketRegistry" p:serviceTicketCountWarnThreshold="5000" p:sessionCountWarnThreshold="100000" /> </util:list> <!-- 訪問本地數據庫 --> <bean id="dbAuthHandler" class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"> <property name="dataSource" ref="dataSource"></property> <property name="sql" value="SELECT PASSWORD_ FROM USER_TABLE WHERE USERNAME_ = ? and ISACTIVE_='Y' "></property> <property name="passwordEncoder" ref="MD5PasswordEncoder"></property> </bean> <!-- SSO密碼加密配置 --> <bean id="MD5PasswordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder"> <constructor-arg index="0"> <value>MD5</value> </constructor-arg> </bean> <!-- mysql連接 --> <!-- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/cas?useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root" /> <property name="password" value="root" /> </bean> --> <!-- oracle連接 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /> <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/> <property name="username" value="username" /> <property name="password" value="password" /> </bean> </beans>
代理端應用配置(app1)注意:文件中${casClientRoot}和${cas.server.url}在properties文件中配置
<?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:s="http://www.springframework.org/schema/security" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> <!-- <s:http pattern="/saveMyCss.json" security="none" /> --> <!-- sso --> <s:http auto-config="true" entry-point-ref="casAuthenticationEntryPoint" servlet-api-provision="true"> <s:intercept-url pattern="/login.jsp" access="ROLE_USER"></s:intercept-url> <s:custom-filter ref="requestSingleLogoutFilter" before="LOGOUT_FILTER" /> <s:custom-filter ref="singleLogoutFilter" before="CAS_FILTER" /> <!-- 增加一個filter,這點與Acegi是不一樣的,不能修改默認的filter了,這個filter位於FILTER_SECURITY_INTERCEPTOR之前--> <s:custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR"/> <s:custom-filter ref="casAuthenticationFilter" position="CAS_FILTER" /> </s:http> <s:authentication-manager alias="authenticationManager"> <s:authentication-provider ref="casAuthenticationProvider"></s:authentication-provider> </s:authentication-manager> <!-- http://localhost:8088/SpringSecurity 具體應用 --> <!-- j_spring_cas_security_check spring的虛擬URL,此標志標識使用 CAS authentication upon return from CAS SSO login. --> <bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties"> <property name="service" value="${casClientRoot}j_spring_cas_security_check"></property> <property name="sendRenew" value="false"></property> </bean> <!-- 配置ProxyGrantingTicketStorage,用以保存pgtId和pgtIou --> <bean id="proxyGrantingTicketStorage" class="org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl"/> <bean id="casAuthenticationFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter"> <property name="authenticationManager" ref="authenticationManager" /> <property name="authenticationSuccessHandler" ref="loginSuccess" /> <property name="authenticationFailureHandler" ref="loginFail" /> <!-- 指定處理地址,不指定時默認將會是“/j_spring_cas_security_check” --> <property name="filterProcessesUrl" value="/j_spring_cas_security_check" /> <!-- 保存cas server傳遞過來的pgtId和pgtIou --> <property name="proxyGrantingTicketStorage" ref="proxyGrantingTicketStorage"/> <!-- 用以指定Cas Server在回調代理端傳遞pgtId和pgtIou時回調地址相對於代理端的路徑 --> <property name="proxyReceptorUrl" value="/proxyCallback"/> </bean> <!-- loginUrl cas 服務登錄地址 --> <bean id="casAuthenticationEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint"> <property name="loginUrl" value="${cas.server.url}login" /> <property name="serviceProperties" ref="serviceProperties" /> </bean> <!-- ticketValidator cas服務驗證地址 --> <bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider"> <property name="userDetailsService" ref="userDetailServiceImpl" /> <property name="serviceProperties" ref="serviceProperties" /> <!-- 配置TicketValidator在登錄認證成功后驗證ticket --> <property name="ticketValidator"> <bean class="org.jasig.cas.client.validation.Cas20ProxyTicketValidator"> <!-- Cas Server訪問地址的前綴,即根路徑--> <!-- cas.server.url https://localhost:8888/cas-server/ --> <constructor-arg index="0" value="${cas.server.url}" /> <!-- 指定Cas Server回調傳遞pgtId和pgtIou的地址,該地址必須使用https協議 --> <!-- casClientRoot https://localhost:8080/app1/ --> <property name="proxyCallbackUrl" value="${casClientRoot}proxyCallback"/> <property name="proxyGrantingTicketStorage" ref="proxyGrantingTicketStorage"/> </bean> </property> <property name="key" value="key4CasAuthenticationProvider" /> </bean> <bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"></bean> <!-- 一個自定義的filter,必須包含authenticationManager,accessDecisionManager,securityMetadataSource三個屬性, 我們的所有控制將在這三個類中實現,解釋詳見具體配置 --> <bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"> <property name="authenticationManager" ref="authenticationManager" /> <property name="accessDecisionManager" ref="dbAccessDecisionManagerBean" /> <property name="securityMetadataSource" ref="securityMetadataSource" /> </bean> <bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" /> <bean id="userDetailServiceImpl" class="com.common.security.UserDetailsServiceImpl"> <property name="dao" ref="dao" /> </bean> <!-- 訪問決策器,決定某個用戶具有的角色,是否有足夠的權限去訪問某個資源 --> <bean id="dbAccessDecisionManagerBean" class="com.common.security.DbAccessDecisionManager"> </bean> <!-- 資源源數據定義,即定義某一資源可以被哪些角色訪問 --> <bean id="securityMetadataSource" class="com.common.security.DbInvocationSecurityMetadataSource"> <property name="securityData" ref="securityData" /> </bean> <bean id="securityData" class="com.common.security.SecurityData"> <property name="dao" ref="dao" /> </bean> <!-- 用戶需要登錄時跳轉的地址 --> <bean id="authenticationEntryPoint" class="com.common.security.AuthenticationEntryPoint"> <property name="loginFormUrl" value="/loginre.jsp" /> </bean> <!-- 用戶登錄失敗 --> <bean id="loginFail" class="com.common.security.LoginFail"> <property name="url" value="login.jsp" /> </bean> <!-- 用戶登錄成功 --> <bean id="loginSuccess" class="com.common.security.loginSuccess"> <property name="url" value="ire.htm" /> </bean> <!-- 注銷客戶端 --> <bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter" /> <!-- 注銷服務器端 --> <bean id="requestSingleLogoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter"> <constructor-arg value="${cas.server.url}logout?service=${casClientRoot}" /> <constructor-arg> <bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/> </constructor-arg> <property name="filterProcessesUrl" value="/j_spring_cas_security_logout" /> </bean> </beans>
被代理端配置(app2)注意:文件中${casClientRoot}和${cas.server.url}在properties文件中配置
<?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:s="http://www.springframework.org/schema/security" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> <!-- <s:http pattern="/saveMyCss.json" security="none" /> --> <!-- sso --> <s:http auto-config="true" entry-point-ref="casAuthenticationEntryPoint" servlet-api-provision="true"> <s:intercept-url pattern="/login.jsp" access="ROLE_USER"></s:intercept-url> <s:custom-filter ref="requestSingleLogoutFilter" before="LOGOUT_FILTER" /> <s:custom-filter ref="singleLogoutFilter" before="CAS_FILTER" /> <!-- 增加一個filter,這點與Acegi是不一樣的,不能修改默認的filter了,這個filter位於FILTER_SECURITY_INTERCEPTOR之前--> <s:custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR"/> <s:custom-filter ref="casAuthenticationFilter" position="CAS_FILTER" /> </s:http> <s:authentication-manager alias="authenticationManager"> <s:authentication-provider ref="casAuthenticationProvider"></s:authentication-provider> </s:authentication-manager> <!-- http://localhost:8088/SpringSecurity 具體應用 --> <!-- j_spring_cas_security_check spring的虛擬URL,此標志標識使用 CAS authentication upon return from CAS SSO login. --> <bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties"> <!-- casClientRoot https://localhost:8080/app2/ --> <property name="service" value="${casClientRoot}j_spring_cas_security_check"></property> <!-- <property name="sendRenew" value="false" /> --> <!-- 通過ServiceProperties指定CasAuthenticationFilter的authenticateAllArtifacts為true --> <property name="authenticateAllArtifacts" value="true"/> </bean> <bean id="casAuthenticationFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter"> <property name="authenticationManager" ref="authenticationManager" /> <property name="authenticationSuccessHandler" ref="loginSuccess" /> <property name="authenticationFailureHandler" ref="loginFail" /> <!-- 指定處理地址,不指定時默認將會是“/j_spring_cas_security_check” --> <property name="filterProcessesUrl" value="/j_spring_cas_security_check" /> <!-- 通過ServiceProperties指定CasAuthenticationFilter的authenticateAllArtifacts為true --> <property name="serviceProperties" ref="serviceProperties" /> <!-- 指定使用的AuthenticationDetailsSource為ServiceAuthenticationDetailsSource --> <property name="authenticationDetailsSource"> <bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource" /> </property> </bean> <!-- loginUrl cas 服務登錄地址 --> <bean id="casAuthenticationEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint"> <property name="loginUrl" value="${cas.server.url}login" /> <property name="serviceProperties" ref="serviceProperties" /> </bean> <!-- ticketValidator cas服務驗證地址 --> <bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider"> <property name="userDetailsService" ref="userDetailServiceImpl" /> <property name="serviceProperties" ref="serviceProperties" /> <!-- 配置TicketValidator在登錄認證成功后驗證ticket --> <property name="ticketValidator"> <bean class="org.jasig.cas.client.validation.Cas20ProxyTicketValidator"> <!-- Cas Server訪問地址的前綴,即根路徑--> <!-- cas.server.url https://localhost:8888/cas-server/ --> <constructor-arg index="0" value="${cas.server.url}" /> <!-- 如果有多個代理端可以多寫幾個value --> <property name="allowedProxyChains"> <value>https://localhost:8080/app1/proxyCallback</value> </property> </bean> </property> <property name="key" value="key4CasAuthenticationProvider" /> <property name="statelessTicketCache"> <bean class="org.springframework.security.cas.authentication.EhCacheBasedTicketCache"> <!-- Ehcache對象 --> <property name="cache" ref="proxyTicketCache"/> </bean> </property> </bean> <!-- 定義一個Ehcache --> <bean id="proxyTicketCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean"> <property name="cacheName" value="proxyTicketCache" /> <property name="timeToLive" value="600"/> </bean> <bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"></bean> <!-- 一個自定義的filter,必須包含authenticationManager,accessDecisionManager,securityMetadataSource三個屬性, 我們的所有控制將在這三個類中實現,解釋詳見具體配置 --> <bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"> <property name="authenticationManager" ref="authenticationManager" /> <property name="accessDecisionManager" ref="dbAccessDecisionManagerBean" /> <property name="securityMetadataSource" ref="securityMetadataSource" /> </bean> <bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" /> <bean id="userDetailServiceImpl" class="com.common.security.UserDetailsServiceImpl"> <property name="dao" ref="dao" /> </bean> <!-- 訪問決策器,決定某個用戶具有的角色,是否有足夠的權限去訪問某個資源 --> <bean id="dbAccessDecisionManagerBean" class="com.common.security.DbAccessDecisionManager"> </bean> <!-- 資源源數據定義,即定義某一資源可以被哪些角色訪問 --> <bean id="securityMetadataSource" class="com.common.security.DbInvocationSecurityMetadataSource"> <property name="securityData" ref="securityData" /> </bean> <bean id="securityData" class="com.common.security.SecurityData"> <property name="dao" ref="dao" /> </bean> <!-- 用戶需要登錄時跳轉的地址 --> <bean id="authenticationEntryPoint" class="com.common.security.AuthenticationEntryPoint"> <property name="loginFormUrl" value="/loginre.jsp" /> </bean> <!-- 用戶登錄失敗 --> <bean id="loginFail" class="com.common.security.LoginFail"> <property name="url" value="login.jsp" /> </bean> <!-- 用戶登錄成功 --> <bean id="loginSuccess" class="com.common.security.loginSuccess"> <property name="url" value="ire.htm" /> </bean> <!-- 注銷客戶端 --> <bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter" /> <!-- 注銷服務器端 --> <bean id="requestSingleLogoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter"> <constructor-arg value="${cas.server.url}logout?service=${casClientRoot}" /> <constructor-arg> <bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/> </constructor-arg> <property name="filterProcessesUrl" value="/j_spring_cas_security_logout" /> </bean> </beans>
代理端請求被代理端的請求
public static String httpURLConnectionPOST(String url) { //1、從SecurityContextHolder獲取到當前的Authentication對象,其是一個CasAuthenticationToken CasAuthenticationToken cat = (CasAuthenticationToken) SecurityContextHolder.getContext() .getAuthentication(); //2、獲取到AttributePrincipal對象 AttributePrincipal principal = cat.getAssertion().getPrincipal(); //3、獲取對應的proxy ticket String proxyTicket = principal.getProxyTicketFor(url); try { //4、請求被代理應用時將獲取到的proxy ticket以參數ticket進行傳遞 url += "?ticket=" + URLEncoder.encode(proxyTicket, "UTF-8"); URL assessUrl = new URL(url); // 將url 以 open方法返回的urlConnection 連接強轉為HttpURLConnection連接 (標識一個url所引用的遠程對象連接) HttpURLConnection connection = (HttpURLConnection) assessUrl.openConnection();// 此時cnnection只是為一個連接對象,待連接中 // 設置連接輸出流為true,默認false (post 請求是以流的方式隱式的傳遞參數) connection.setDoOutput(true); // 設置連接輸入流為true connection.setDoInput(true); // 設置請求方式為post connection.setRequestMethod("POST"); // post請求緩存設為false connection.setUseCaches(false); // 設置該HttpURLConnection實例是否自動執行重定向 connection.setInstanceFollowRedirects(true); // 設置請求頭里面的各個屬性 (以下為設置內容的類型,設置為經過urlEncoded編碼過的from參數) // application/x-javascript text/xml->xml數據 application/x-javascript->json對象 application/x-www-form-urlencoded->表單數據 // ;charset=utf-8 必須要,不然妙兜那邊會出現亂碼【★★★★★】 connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded;charset=utf-8"); // 建立連接 (請求未開始,直到connection.getInputStream()方法調用時才發起,以上各個參數設置需在此方法之前進行) connection.connect(); // 創建輸入輸出流,用於往連接里面輸出攜帶的參數,(輸出內容為?后面的內容) DataOutputStream dataout = new DataOutputStream(connection.getOutputStream()); // 輸出完成后刷新並關閉流 dataout.flush(); dataout.close(); // 重要且易忽略步驟 (關閉流,切記!) //System.out.println(connection.getResponseCode()); // 連接發起請求,處理服務器響應 (從連接獲取到輸入流並包裝為bufferedReader) BufferedReader bf = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8")); String line; StringBuilder sb = new StringBuilder(); // 用來存儲響應數據 // 循環讀取流,若不到結尾處 while ((line = bf.readLine()) != null) { // sb.append(bf.readLine()); sb.append(line).append(System.getProperty("line.separator")); } bf.close(); // 重要且易忽略步驟 (關閉流,切記!) connection.disconnect(); // 銷毀連接 return sb.toString(); } catch (Exception e) { e.printStackTrace(); } return null; }
被代理端的接口
@RequestMapping(value = "/testPost.json") public void synUser( String xmlPath) throws Exception { System.out.println(xmlPath); }
public static String httpURLConnectionPOST(String url) { //1、從SecurityContextHolder獲取到當前的Authentication對象,其是一個CasAuthenticationToken CasAuthenticationToken cat = (CasAuthenticationToken) SecurityContextHolder.getContext() .getAuthentication(); //2、獲取到AttributePrincipal對象 AttributePrincipal principal = cat.getAssertion().getPrincipal(); //3、獲取對應的proxy ticket String proxyTicket = principal.getProxyTicketFor(url); try { //4、請求被代理應用時將獲取到的proxy ticket以參數ticket進行傳遞 url += "?ticket=" + URLEncoder.encode(proxyTicket, "UTF-8"); URL assessUrl = new URL(url); // 將url 以 open方法返回的urlConnection 連接強轉為HttpURLConnection連接 (標識一個url所引用的遠程對象連接) HttpURLConnection connection = (HttpURLConnection) assessUrl.openConnection();// 此時cnnection只是為一個連接對象,待連接中 // 設置連接輸出流為true,默認false (post 請求是以流的方式隱式的傳遞參數) connection.setDoOutput(true); // 設置連接輸入流為true connection.setDoInput(true); // 設置請求方式為post connection.setRequestMethod("POST"); // post請求緩存設為false connection.setUseCaches(false); // 設置該HttpURLConnection實例是否自動執行重定向 connection.setInstanceFollowRedirects(true); // 設置請求頭里面的各個屬性 (以下為設置內容的類型,設置為經過urlEncoded編碼過的from參數) // application/x-javascript text/xml->xml數據 application/x-javascript->json對象 application/x-www-form-urlencoded->表單數據 // ;charset=utf-8 必須要,不然妙兜那邊會出現亂碼【★★★★★】 connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded;charset=utf-8"); // 建立連接 (請求未開始,直到connection.getInputStream()方法調用時才發起,以上各個參數設置需在此方法之前進行) connection.connect(); // 創建輸入輸出流,用於往連接里面輸出攜帶的參數,(輸出內容為?后面的內容) DataOutputStream dataout = new DataOutputStream(connection.getOutputStream()); // 輸出完成后刷新並關閉流 dataout.flush(); dataout.close(); // 重要且易忽略步驟 (關閉流,切記!)
//System.out.println(connection.getResponseCode());
// 連接發起請求,處理服務器響應 (從連接獲取到輸入流並包裝為bufferedReader) BufferedReader bf = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8")); String line; StringBuilder sb = new StringBuilder(); // 用來存儲響應數據
// 循環讀取流,若不到結尾處 while ((line = bf.readLine()) != null) { // sb.append(bf.readLine()); sb.append(line).append(System.getProperty("line.separator")); } bf.close(); // 重要且易忽略步驟 (關閉流,切記!) connection.disconnect(); // 銷毀連接 return sb.toString(); } catch (Exception e) { e.printStackTrace(); } return null; }