cas 服务端配置
1 .支持Http
修改 WEB-INF\deployerConfigContext.xml
增加参数 p:requireSecure="false" ,是否需要安全验证,即 HTTPS , false 为不采用 <bean id="proxyAuthenticationHandler" class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler" p:httpClient-ref="supportsTrustStoreSslSocketFactoryHttpClient" p:requireSecure="false" />
修改 WEB-INF\spring-configuration/ticketGrantingTicketCookieGenerator.xml
修改 p:cookieSecure="true" 为 p:cookieSecure=" false " , 即不需要安全 cookie <bean id="ticketGrantingTicketCookieGenerator" class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator" c:casCookieValueManager-ref="cookieValueManager" p:cookieSecure="false" p:cookieMaxAge="-1" p:cookieName="TGC" p:cookiePath=""/>
修改 WEB-INF\spring-configuration\warnCookieGenerator.xml
修改 p:cookieSecure="true" 为 p:cookieSecure=" false " , 即不需要安全 cookie <bean id="warnCookieGenerator" class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator" p:cookieHttpOnly="true" p:cookieSecure="false" p:cookieMaxAge="-1" p:cookieName="CASPRIVACY" p:cookiePath=""/>
修改注册服务WEB-INF/classes/services/HTTPSandIMAPS-10000001.json
将"serviceId" : "^(https|imaps)://.*"修改为"serviceId" : "^(https|http|imaps)://.*"
2.支持数据库认证
1.注释掉默认的用户认证
<!--<bean id="primaryAuthenticationHandler"
class="org.jasig.cas.authentication.AcceptUsersAuthenticationHandler">
<property name="users">
<map>
<entry key="casuser" value="Mellon"/>
</map>
</property>
</bean>-->
2.添加JDBC验证方式
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@123.56.74.172:1521:orcl" />
<property name="username" value="zjk" />
<property name="password" value="zjk" />
</bean>
<bean id="primaryAuthenticationHandler"
class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"
p:dataSource-ref="dataSource"
p:passwordEncoder-ref="MD5PasswordEncoder"
p:sql="select lower(LOGON_PWD) password from ams_user where LOGON_ACCT=?" />
<bean id="MD5PasswordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder">
<constructor-arg index="0">
<value>MD5</value>
</constructor-arg>
</bean>
3.添加jar包
将cas-server-support-jdbc-4.1.10.jar,commons-dbcp2-2.1.1.jar,ojdbc6.jar三个包拷贝到WEB-INF/lib上
3.支持REST API
1.添加jar包
将cas-server-support-rest-4.1.10.jar包拷贝到WEB-INF/lib上
4.支持OAuth 2.0
修改 WEB-INF\web.xml
添加路由映射 <servlet-mapping> <servlet-name>cas</servlet-name> <url-pattern>/oauth2.0/*</url-pattern> </servlet-mapping>
修改 WEB-INF\cas-servlet.xml
在文件中添加bean <bean id="oauth20WrapperController" class="org.jasig.cas.support.oauth.web.OAuth20WrapperController" p:loginUrl="http://127.0.0.1:8080/cas/login" p:servicesManager-ref="servicesManager" p:ticketRegistry-ref="ticketRegistry" p:timeout="7200" /> 在handlerMappingC的bean中添加属性 <prop key="/oauth2.0/*">oauth20WrapperController</prop>
添加OAuth2客户端(在WEB-INF/classes/services/文件夹下添加服务定义的json)
{ "@class" : "org.jasig.cas.support.oauth.services.OAuthRegisteredService", "serviceId" : "oauth client service url", "name" : "serviceName", "id" : 1, "description" : "Service Description", "clientId":"client id goes here", "clientSecret":"client secret goes here" }
5:修改cas来源登录退出页面
- cas
- css (样式)
- img (图片)
- js (js)
登录页面和退出页面
路径 cas\WEB-INF\view\jsp\default\ui 下
登入页面casLoginView.jsp , /includes/login_top.jsp , /includes/bottom.jsp
退出页面casLogoutView.jsp, /includes/logout_top.jsp,/includes/bottom.jsp
建议修改页面时先备份下原来的
在login_top.jsp中引入自己的样式
<link rel="stylesheet" href="css/normalize.css" />
<link rel="stylesheet" href="css/login.css" />
在casLoginView.jsp中修改自己的html
cas 默认只提供username 和password 两个变量,如果需要新增请看后面
下面的修改时请谨慎
<form:form method="post" id="fm1" commandName="${commandName}" htmlEscape="true">
<form:errors path="*" id="msg" cssClass="errors" element="div" htmlEscape="false" />
<c:choose>
<c:when test="${not empty sessionScope.openIdLocalId}">
<strong><c:out value="${sessionScope.openIdLocalId}" /></strong>
<input type="hidden" id="username" name="username" value="<c:out value="${sessionScope.openIdLocalId}" />" />
</c:when>
<c:otherwise>
<spring:message code="screen.welcome.label.netid.accesskey" var="userNameAccessKey" /> <!--不能删 -->
<form:input cssClass="required" cssErrorClass="error" id="username" size="25" tabindex="1" accesskey="${userNameAccessKey}" path="username" autocomplete="off" htmlEscape="true" placeholder="账号" />
</c:otherwise>
</c:choose>
</div>
<div class="password-box t">
<spring:message code="screen.welcome.label.password.accesskey" var="passwordAccessKey" /> <!--不能删 -->
<form:password cssClass="required" cssErrorClass="error" class="password input-height" id="password" size="25" tabindex="2" path="password" accesskey="${passwordAccessKey}" htmlEscape="true" autocomplete="off" placeholder="密码"/>
</div>
<section class="row btn-row login-box" style="margin-top: 53px;">
<input type="hidden" name="lt" value="${loginTicket}" />
<input type="hidden" name="execution" value="${flowExecutionKey}" />
<input type="hidden" name="_eventId" value="submit" />
<!--不能删 -->
<input class="btn-submit btn-login btn-blue" name="submit" accesskey="l" value="登录" tabindex="6" type="submit" />
</section>
</form:form>
修改信息在classes/messages.properties
如:
authenticationFailure.AccountNotFoundException=用户名或密码错误
authenticationFailure.FailedLoginException=用户名或密码错误
6.cas配置多数据源
deployerConfigContext.xml
配置两个dateSource
<bean id="dataSource1"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl" />
<property name="username" value="username" />
<property name="password" value="password" />
</bean>
<bean id="dataSource2"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl" />
<property name="username" value="username" />
<property name="password" value="password" />
</bean>
配置两个登入权限处理
deployerConfigContext.xml
<bean id="primaryAuthenticationHandler"
class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"
p:dataSource-ref="dataSource1"
p:passwordEncoder-ref="MD5PasswordEncoder"
p:sql="select lower(LOGON_PWD) password from t_user where LOGON_ACCT=?" />
<bean id="secondAuthenticationHandler"
class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"
p:dataSource-ref="dataSource2"
p:passwordEncoder-ref="MD5PasswordEncoder"
p:sql="select lower(USER_PWD) password from t_user2 where USER_ACCT=?" />
配置 PrincipalResolver
deployerConfigContext.xml
<bean id="primaryPrincipalResolver"
class="org.jasig.cas.authentication.principal.PersonDirectoryPrincipalResolver"
p:principalFactory-ref="principalFactory"
p:attributeRepository-ref="attributeRepository" />
<bean id="secondPrincipalResolver"
class="org.jasig.cas.authentication.principal.PersonDirectoryPrincipalResolver"
p:principalFactory-ref="principalFactory"
p:attributeRepository-ref="attributeRepository" />
最后配置secondPrincipalResolver
deployerConfigContext.xml
<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" />
<entry key-ref="secondAuthenticationHandler" value-ref="secondPrincipalResolver" />
<!-- 多出这里一句-->
</map>
</constructor-arg>
7. 返回多个用户信息
cas默认返回用户名,但是在实际生产中往往不止则一个数据,那么就需要我们在查询一遍数据库获得数据
deployerConfigContext.xml
<bean id="primaryAttributeRepository" class="org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao">
<constructor-arg index="0" ref="dataSource" />
<constructor-arg index="1" value="select user_id,'ams' source from t_user where {0}" />
<property name="queryAttributeMapping">
<map>
<entry key="username" value="LOGON_ACCT" />
</map>
</property>
<property name="resultAttributeMapping">
<map>
<!-- key是数据库的字段 赋值给 userId变量 -->
<entry key="user_id" value="userId" />
<entry key="source" value="source"/>
</map>
</property>
</bean>
8.设置过期时间
在ticketExpirationPolicies.xml中
<!-- TicketGrantingTicketExpirationPolicy: Default as of 3.5 -->
<!-- Provides both idle and hard timeouts, for instance 2 hour sliding window with an 8 hour max lifetime -->
<bean id="grantingTicketExpirationPolicy" class="org.jasig.cas.ticket.support.TicketGrantingTicketExpirationPolicy"
c:maxTimeToLive="${tgt.maxTimeToLiveInSeconds:86400}" c:timeToKill="${tgt.timeToKillInSeconds:43200}" c:timeUnit-ref="SECONDS" />
9.区别登录
区别登录已经脱离cas,但是我之前坑爹的需求就要这么做,没办法只能修改原代码,这里放出来,是因为其中是有用的一些信息,包括自定义参数上传等。
需要修改源代码,下载源代码
cas sql 默认只支持传username
final String dbPassword = getJdbcTemplate().queryForObject(this.sql, String.class, username);
if (!dbPassword.equals(encryptedPassword)) {
hrow new FailedLoginException("Password does not match value on record.");
}
解决方法:
* 多传一个来源,根据来源和sql匹配看看是不是有存在相同字符,如果存在就执行该sql,不存在就是直接报密码错误 *
1:修改源代码:cas-server-core jar包
org.jasig.cas.authentication 包下
新增类
package org.jasig.cas.authentication;
/**
* @author ErnestCheng
* @since 1.0
* 2017-08-17
*/
public class MyCredential extends UsernamePasswordCredential {
private String usertype; //用户类型
public final String getUsertype() {
return usertype;
}
public final void setUsertype(String usertype) {
this.usertype = usertype;
}
}
2: 修改源代码 :cas-server-support-jdbc jar包
org.jasig.cas.adaptors.jdbc 包下
新增类
package org.jasig.cas.adaptors.jdbc;
import javax.security.auth.login.AccountNotFoundException;
import javax.security.auth.login.FailedLoginException;
import javax.validation.constraints.NotNull;
import org.jasig.cas.authentication.HandlerResult;
import org.jasig.cas.authentication.MyCredential;
import org.jasig.cas.authentication.PreventedException;
import org.jasig.cas.authentication.UsernamePasswordCredential;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import java.security.GeneralSecurityException;
/**
* @author ErnestCheng
* @since 1.0
* 2017-08-17
*/
public class MyAuthenticationHandler extends AbstractJdbcUsernamePasswordAuthenticationHandler{
@NotNull
private String sql;
@Override
protected HandlerResult authenticateUsernamePasswordInternal(UsernamePasswordCredential credential) throws GeneralSecurityException, PreventedException {
MyCredential myCredential=null;
if(MyCredential.class.isInstance(credential)){
myCredential=(MyCredential)credential;
}else{
throw new IllegalAccessError("验证参数不匹配");
}
final String username = myCredential.getUsername();
final String password=myCredential.getPassword();
final String encryptedPassword = this.getPasswordEncoder().encode(password);
final String userType=myCredential.getUsertype();
try {
if(this.sql.contains(userType) || this.sql.contains(userType.toUpperCase())) {
final String dbPassword = getJdbcTemplate().queryForObject(this.sql, String.class, username);
if (!dbPassword.equals(encryptedPassword)) {
throw new FailedLoginException("Password does not match value on record.");
}
}else{
throw new FailedLoginException("Password does not match value on record.");
}
} catch (final IncorrectResultSizeDataAccessException e) {
if (e.getActualSize() == 0) {
throw new AccountNotFoundException(username + " not found with SQL query");
} else {
throw new FailedLoginException("Multiple records " + username);
}
} catch (final DataAccessException e) {
throw new PreventedException("SQL exception while executing query for " + username, e);
}
return createHandlerResult(myCredential, this.principalFactory.createPrincipal(username), null);
}
/**
* @param sql The sql to set.
*/
public void setSql(final String sql) {
this.sql = sql;
}
}
3: 新增自定义参数
在 Web-inf\webflow\login\login-webflow.xml 下
<view-state id="viewLoginForm" view="casLoginView" model="credential">
<binder>
<binding property="username" required="true"/>
<binding property="password" required="true"/>
<binding property="usertype" required="false"/>
<!-- 这里可以新增自定义参数 -->
</binder>
<on-entry>
<set name="viewScope.commandName" value="'credential'"/>
<!--
<evaluate expression="samlMetadataUIParserAction" />
-->
</on-entry>
<transition on="submit" bind="true" validate="true" to="realSubmit"/>
</view-state>
4:修改参数接受类
在 Web-inf\webflow\login\login-webflow.xml 下
UsernamePasswordCredential 改成 MyCredential
<var name="credential" class="org.jasig.cas.authentication.MyCredential"/>
5:修改处理类
在 web-inf\deployerConfigContext.xml
QueryDatabaseAuthenticationHandler 改成MyAuthenticationHandler
<bean id="primaryAuthenticationHandler"
class="org.jasig.cas.adaptors.jdbc.MyAuthenticationHandler"
p:dataSource-ref="dataSource"
p:passwordEncoder-ref="MD5PasswordEncoder"
p:sql="select lower(LOGON_PWD) password from ams_user where LOGON_ACCT=? and USER_TYPE_ID='2'" />
6:新增页面自定义参数
在 web-inf\view\jsp\default\ui\casLoginView.jsp
<div class="password-box t" style="display:none">
<form:input cssClass="required password input-height" cssErrorClass="error " class="password input-height" id="usertype" size="25" tabindex="2" path="usertype" htmlEscape="true" autocomplete="off" placeholder="来源"/>
</div>
<script type="text/javascript">
var url=document.location.href;
function isContains(url, source) {
return url.indexOf(source) >= 0;
}
if(isContains(url,'ts')){
document.getElementById("usertype").value='ams_user';
}else if(isContains(url,'op')){
document.getElementById("usertype").value='op_user';
}
</script>