cas单点登录被广泛运用在多系统集成进行统一的登录登出管理,网上资料也比较多,这里就不作过多的描述。写这篇博客目的主要还是为了记录下以方便日后使用。
1.准备步骤
下载cas4.0源码包 官网http://jasig.github.io/cas/4.0.0/index.html
导入IDE
2.功能拓展
1.首先当然是拓展认证方式,cas 默认给的为简单的用户名等于密码的认证 这种实际应用中当然是没法使用的,一般我们都会用jdbc的认证方式
deployerConfigContext.xml 中 找到 id为 primaryAuthenticationHandler的bean 修改为
<bean id="primaryAuthenticationHandler" class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
<property name="dataSource" ref="dataSource" ></property>
<property name="sql" value="select password from t_user where login_name=?" ></property>
<property name="passwordEncoder" ref="MD5PasswordEncoder" ></property>
</bean>
当然这里可以自定义拓展认证,只需要继承 AbstractJdbcUsernamePasswordAuthenticationHandler 这里就直接贴代码了
import java.security.GeneralSecurityException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.security.auth.login.AccountNotFoundException;
import javax.security.auth.login.FailedLoginException;
import javax.validation.constraints.NotNull;
import org.jasig.cas.adaptors.jdbc.AbstractJdbcUsernamePasswordAuthenticationHandler;
import org.jasig.cas.authentication.HandlerResult;
import org.jasig.cas.authentication.PreventedException;
import org.jasig.cas.authentication.UsernamePasswordCredential;
import org.jasig.cas.authentication.principal.SimplePrincipal;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import com.cn.instai.cas.credential.CustomUsernamePasswordCredential;
public class CustomDatabaseAuthenticationHandler extends
AbstractJdbcUsernamePasswordAuthenticationHandler {
@NotNull
private String sql;
@Override
protected HandlerResult authenticateUsernamePasswordInternal(
UsernamePasswordCredential credential) throws GeneralSecurityException,
PreventedException {
// TODO Auto-generated method stub
final String username = credential.getUsername();
final String encryptedPassword = this.getPasswordEncoder().encode(credential.getPassword()+credential.getPassword());
String md5Password = this.getPasswordEncoder().encode(username+encryptedPassword);
try {
//final String schoolCode = getJdbcTemplate().queryForObject(SELECT_SCHOOL_CODE_SQL,String.class,requestUrl);
final String dbPassword = getJdbcTemplate().queryForObject(this.sql, String.class, username);
if (!dbPassword.equals(md5Password)) {
throw new FailedLoginException("密码不正确");
}
} catch (final IncorrectResultSizeDataAccessException e) {
e.printStackTrace();
if (e.getActualSize() == 0) {
throw new AccountNotFoundException(username + "账号不存在");
} else {
throw new FailedLoginException("登录失败 " + username);
}
} catch (final DataAccessException e) {
e.printStackTrace();
throw new PreventedException("SQL exception while executing query for " + username, e);
}
return createHandlerResult(credential, new SimplePrincipal(username), null);
}
public void setSql(final String sql) {
this.sql = sql;
}
}
2.返回更多用户信息
同样在deployerConfigContext.xml文件中 attributeRepository bean
<bean id= "attributeRepository" class="org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao" >
<constructor-arg index= "0" ref ="dataSource"/>
<constructor-arg index= "1" value ="SELECT * FROM T_BASE_USER WHERE {0} AND USER_STATUS IN (1,2)" />
<property name= "queryAttributeMapping" >
<map>
<entry key= "username" value ="USER_LOGIN_NAME" />
</map>
</property>
<property name="resultAttributeMapping" >
<map>
<entry key="USER_ACTUAL_NAME" value ="userName"/>
<entry key="SCHOOL_CODE" value="schoolCode" />
<entry key="USER_ID" value="userId" />
<entry key="USER_TYPE" value="userType"/>
</map>
</property>
</bean >
然后配置验证成功页面 添加返回的信息
<cas:authenticationSuccess>
<cas:user>${fn:escapeXml(assertion.primaryAuthentication.principal.id)}</cas:user>
<%--添加登录成功返回信息 --%>
<c:if test="${fn:length(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes) > 0}">
<cas:attributes>
<c:forEach var="attr" items="${assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes}">
<cas:${fn:escapeXml(attr.key)}>${fn:escapeXml(attr.value)}</cas:${fn:escapeXml(attr.key)}>
</c:forEach>
</cas:attributes>
</c:if>
<c:if test="${not empty pgtIou}">
<cas:proxyGrantingTicket>${pgtIou}</cas:proxyGrantingTicket>
</c:if>
<c:if test="${fn:length(assertion.chainedAuthentications) > 1}">
<cas:proxies>
<c:forEach var="proxy" items="${assertion.chainedAuthentications}" varStatus="loopStatus" begin="0" end="${fn:length(assertion.chainedAuthentications)-2}" step="1">
<cas:proxy>${fn:escapeXml(proxy.principal.id)}</cas:proxy>
</c:forEach>
</cas:proxies>
</c:if>
</cas:authenticationSuccess>