本篇教程cas-server端下載地址:解壓後,直接放到tomcat的webapp目錄下就能用了,不過你須要登陸的話,要修改數據源,C:\tomcat7\webapps\casServer\WEB-INF\deployerConfigContext.xmljavascript
落雨 cas 單點登陸
html
環境:
java
server端:cas-server-core-3.5.2.jar、cas-client-core-3.2.1.jarweb
client端:cas-client-core-3.1.3.jar、http屏蔽了https後的casclient.jar(http://blog.csdn.NET/dengtaowei/article/details/7039399)spring
以前作的界面裏面缺乏一個驗證碼的功能,上週因爲搞其餘事情去了,就沒有開始驗證碼的教程寫做,今天補上,但願能按照教程製做出大家想要的功能。express
結果圖:apache
至此爲止,五篇教程,自定義的Java類不是不少,還不是很深刻。包結構和jar包以下圖,程序去個人csdn下載頻道下載。數組
C:\TOMCAT7\WEBAPPS\CASSERVER\WEB-INF\CLASSES\ORG
└─jasig
└─cas
├─authentication
│ └─handler
│ │ CaptchaImageLoginCredentials.class
│ │ Crypt.class
│ │ ImageVaditeAuthenticationViaFormAction.class
│ │ MD5.class
│ │ RsCasDaoAuthenticationHandler.class
│ │
│ ├─captchaImage
│ │ CaptchaImageCreateController.class
│ │
│ └─util
│ ValidatorCodeUtil$ValidatorCode.class
│ ValidatorCodeUtil.class
│
├─util
│ AutowiringSchedulerFactoryBean.class
│
└─web
│ FlowExecutionExceptionResolver.class
│
└─flow
GatewayServicesManagementCheck.class
ServiceAuthorizationCheck.class
緩存
1.cas-servlet.xml tomcat
.找到C:\tomcat7\webapps\casServer\WEB-INF\cas-servlet.xml文件,在
bean id="handlerMappingC" 節點下增長
- <span style="font-family:Microsoft YaHei;font-size:14px;"><bean
- id="handlerMappingC"
- class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
- <property name="mappings">
- <props>
- <prop key="/logout">logoutController</prop>
- <prop key="/serviceValidate">serviceValidateController</prop>
- <prop key="/validate">legacyValidateController</prop>
- <prop key="/proxy">proxyController</prop>
- <prop key="/proxyValidate">proxyValidateController</prop>
- <prop key="/samlValidate">samlValidateController</prop>
- <prop key="/services/add.html">addRegisteredServiceSimpleFormController</prop>
- <prop key="/services/edit.html">editRegisteredServiceSimpleFormController</prop>
- <prop key="/services/loggedOut.html">serviceLogoutViewController</prop>
- <prop key="/services/viewStatistics.html">viewStatisticsController</prop>
- <prop key="/services/*">manageRegisteredServicesMultiActionController</prop>
- <prop key="/openid/*">openIdProviderController</prop>
- <prop key="/authorizationFailure.html">passThroughController</prop>
- <prop key="/403.html">passThroughController</prop>
- <prop key="/status">healthCheckController</prop>
-
- <prop key="/captcha.htm">captchaImageCreateController</prop>
-
- </props>
- </property>
- <property
- name="alwaysUseFullPath" value="true"/>
- <!--
- uncomment this to enable sending PageRequest events.
- <property
- name="interceptors">
- <list>
- <ref bean="pageRequestHandlerInterceptorAdapter" />
- </list>
- </property>
- -->
- </bean></span>
captchaImageCreateController須要咱們本身寫java類
在上述xml代碼後面繼續添加一個bean,以下,而類class路徑是咱們本身寫的,在myeclipse裏面本身diy的包名org.jasig.cas.authentication.handler.captchaImage.CaptchaImageCreateController
- <span style="font-family:Microsoft YaHei;font-size:14px;">
- <bean id="captchaImageCreateController" class="org.jasig.cas.authentication.handler.captchaImage.CaptchaImageCreateController"></bean></span>
2.而後咱們開始寫這個CaptchaImageCreateController類
org.jasig.cas.authentication.handler.captchaImage.CaptchaImageCreateController
CaptchaImageCreateController.java
-
- package org.jasig.cas.authentication.handler.captchaImage;
- import java.io.IOException;
-
- import javax.servlet.ServletOutputStream;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
- import org.jasig.cas.authentication.handler.util.ValidatorCodeUtil;
- import org.jasig.cas.authentication.handler.util.ValidatorCodeUtil.ValidatorCode;
-
- import org.springframework.beans.factory.InitializingBean;
- import org.springframework.web.servlet.ModelAndView;
- import org.springframework.web.servlet.mvc.Controller;
-
- import com.sun.image.codec.jpeg.JPEGCodec;
- import com.sun.image.codec.jpeg.JPEGImageEncoder;
-
- public class CaptchaImageCreateController implements Controller, InitializingBean {
-
- public void afterPropertiesSet() throws Exception {
-
- }
-
- public ModelAndView handleRequest(HttpServletRequest arg0,
- HttpServletResponse response) throws Exception {
- ValidatorCode codeUtil = ValidatorCodeUtil.getCode();
- System.out.println("code="+codeUtil.getCode());
-
- arg0.getSession().setAttribute("code", codeUtil.getCode());
-
- response.setHeader("Pragma", "no-cache");
- response.setHeader("Cache-Control", "no-cache");
- response.setDateHeader("Expires", 0);
- response.setContentType("image/jpeg");
-
- ServletOutputStream sos = null;
- try {
-
- sos = response.getOutputStream();
- JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(sos);
- encoder.encode(codeUtil.getImage());
- sos.flush();
- sos.close();
- } catch (Exception e) {
- } finally {
- if (null != sos) {
- try {
- sos.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- return null;
- }
- }
3.開始搞驗證碼圖片生成java類的編寫:
這個類中用到了網上常常用的驗證碼生成類,這個類你能夠本身隨便寫,下面提供一個網上寫的,生成的驗證碼挺漂亮的。
import org.jasig.cas.authentication.handler.util.ValidatorCodeUtil;
import org.jasig.cas.authentication.handler.util.ValidatorCodeUtil.ValidatorCode;
ValidatorCode類是ValidatorCodeUtil類的一個內部類,代碼以下
ValidatorCode.java
-
- package org.jasig.cas.authentication.handler.util;
-
- import java.awt.Color;
- import java.awt.Font;
- import java.awt.Graphics2D;
- import java.awt.image.BufferedImage;
- import java.util.Random;
- public class ValidatorCodeUtil {
- public static ValidatorCode getCode() {
-
- int width = 80;
-
- int height = 30;
- BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
- Graphics2D g = buffImg.createGraphics();
-
-
- Random random = new Random();
-
-
- g.setColor(Color.WHITE);
- g.fillRect(0, 0, width, height);
-
- Font font = new Font("微軟雅黑", Font.HANGING_BASELINE, 28);
-
- g.setFont(font);
-
-
- g.setColor(Color.BLACK);
- g.drawRect(0, 0, width - 1, height - 1);
-
-
-
-
-
-
-
-
-
-
-
-
- StringBuffer randomCode = new StringBuffer();
-
-
- int length = 4;
-
- String base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-
- int size = base.length();
-
-
- for (int i = 0; i < length; i++) {
-
- int start = random.nextInt(size);
- String strRand = base.substring(start, start + 1);
-
-
-
-
-
-
- g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
- g.drawString(strRand, 15 * i + 6, 24);
-
-
- randomCode.append(strRand);
- }
-
-
- g.dispose();
- ValidatorCode code = new ValidatorCode();
- code.image = buffImg;
- code.code = randomCode.toString();
- return code;
- }
-
-
- static Color getRandColor(int fc, int bc) {
- Random random = new Random();
- if (fc > 255)
- fc = 255;
- if (bc > 255)
- bc = 255;
- int r = fc + random.nextInt(bc - fc);
- int g = fc + random.nextInt(bc - fc);
- int b = fc + random.nextInt(bc - fc);
- return new Color(r, g, b);
- }
-
-
- public static class ValidatorCode {
- private BufferedImage image;
- private String code;
-
-
- public BufferedImage getImage() {
- return image;
- }
-
-
- public String getCode() {
- return code;
- }
- }
- }
4.驗證碼生成作完了,那麼咱們開始修改默認的認證器的認證方式,增長驗證碼驗證
本身新建一個java類:
ImageVaditeAuthenticationViaFormAction.java,此類實際上是改造的org.jasig.cas.web.flow.AuthenticationViaFormAction.java這個類,它裏面原本只是驗證用戶名和密碼,咱們增長一個成員變量,code,而後在驗證用戶名和密碼以前,咱們先開始驗證驗證碼。
- package org.jasig.cas.authentication.handler;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.validation.constraints.NotNull;
-
- import org.jasig.cas.CentralAuthenticationService;
- import org.jasig.cas.authentication.handler.AuthenticationException;
- import org.jasig.cas.authentication.principal.Credentials;
- import org.jasig.cas.authentication.principal.Service;
- import org.jasig.cas.ticket.TicketException;
- import org.jasig.cas.web.bind.CredentialsBinder;
- import org.jasig.cas.web.support.WebUtils;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.binding.message.MessageBuilder;
- import org.springframework.binding.message.MessageContext;
- import org.springframework.util.StringUtils;
- import org.springframework.web.util.CookieGenerator;
- import org.springframework.webflow.execution.RequestContext;
-
- public class ImageVaditeAuthenticationViaFormAction {
-
-
- private String code = "code";
-
-
- private CredentialsBinder credentialsBinder;
-
-
- @NotNull
- private CentralAuthenticationService centralAuthenticationService;
-
- @NotNull
- private CookieGenerator warnCookieGenerator;
-
- protected Logger logger = LoggerFactory.getLogger(getClass());
-
- public final void doBind(final RequestContext context, final Credentials credentials) throws Exception {
- final HttpServletRequest request = WebUtils.getHttpServletRequest(context);
-
- if (this.credentialsBinder != null && this.credentialsBinder.supports(credentials.getClass())) {
- this.credentialsBinder.bind(request, credentials);
- }
- }
-
- public final String submit(final RequestContext context, final Credentials credentials, final MessageContext messageContext) throws Exception {
-
-
- if (credentials instanceof CaptchaImageLoginCredentials) {
-
- CaptchaImageLoginCredentials rmupc = (CaptchaImageLoginCredentials) credentials;
-
- String sessionCode = (String) WebUtils.getHttpServletRequest(context).getSession().getAttribute(code);
-
-
- if (rmupc.getCode() == null) {
-
- logger.warn("驗證碼爲空");
-
- final String code = "login.code.tip";
-
- messageContext.addMessage(new MessageBuilder().error().code(code).arg("").defaultText(code).build());
- return "error";
- }
-
- if (!rmupc.getCode().toUpperCase().equals(sessionCode.toUpperCase())) {
- logger.warn("驗證碼檢驗有誤");
- final String code = "login.code.error";
- messageContext.addMessage(new MessageBuilder().error().code(code).arg("").defaultText(code).build());
- return "error";
- }
-
- }
-
-
- final String authoritativeLoginTicket = WebUtils.getLoginTicketFromFlowScope(context);
- final String providedLoginTicket = WebUtils.getLoginTicketFromRequest(context);
- if (!authoritativeLoginTicket.equals(providedLoginTicket)) {
- this.logger.warn("Invalid login ticket " + providedLoginTicket);
- final String code = "INVALID_TICKET";
- messageContext.addMessage(new MessageBuilder().error().code(code).arg(providedLoginTicket).defaultText(code).build());
- return "error";
- }
-
- final String ticketGrantingTicketId = WebUtils.getTicketGrantingTicketId(context);
- final Service service = WebUtils.getService(context);
- if (StringUtils.hasText(context.getRequestParameters().get("renew")) && ticketGrantingTicketId != null && service != null) {
-
- try {
- final String serviceTicketId = this.centralAuthenticationService.grantServiceTicket(ticketGrantingTicketId, service, credentials);
- WebUtils.putServiceTicketInRequestScope(context, serviceTicketId);
- putWarnCookieIfRequestParameterPresent(context);
- return "warn";
- } catch (final TicketException e) {
- if (isCauseAuthenticationException(e)) {
- populateErrorsInstance(e, messageContext);
- return getAuthenticationExceptionEventId(e);
- }
-
- this.centralAuthenticationService.destroyTicketGrantingTicket(ticketGrantingTicketId);
- if (logger.isDebugEnabled()) {
- logger.debug("Attempted to generate a ServiceTicket using renew=true with different credentials", e);
- }
- }
- }
-
- try {
- WebUtils.putTicketGrantingTicketInRequestScope(context, this.centralAuthenticationService.createTicketGrantingTicket(credentials));
- putWarnCookieIfRequestParameterPresent(context);
- return "success";
- } catch (final TicketException e) {
- populateErrorsInstance(e, messageContext);
- if (isCauseAuthenticationException(e))
- return getAuthenticationExceptionEventId(e);
- return "error";
- }
- }
-
- private void populateErrorsInstance(final TicketException e, final MessageContext messageContext) {
-
- try {
- messageContext.addMessage(new MessageBuilder().error().code(e.getCode()).defaultText(e.getCode()).build());
- } catch (final Exception fe) {
- logger.error(fe.getMessage(), fe);
- }
- }
-
- private void putWarnCookieIfRequestParameterPresent(final RequestContext context) {
- final HttpServletResponse response = WebUtils.getHttpServletResponse(context);
-
- if (StringUtils.hasText(context.getExternalContext().getRequestParameterMap().get("warn"))) {
- this.warnCookieGenerator.addCookie(response, "true");
- } else {
- this.warnCookieGenerator.removeCookie(response);
- }
- }
-
- private AuthenticationException getAuthenticationExceptionAsCause(final TicketException e) {
- return (AuthenticationException) e.getCause();
- }
-
- private String getAuthenticationExceptionEventId(final TicketException e) {
- final AuthenticationException authEx = getAuthenticationExceptionAsCause(e);
-
- if (this.logger.isDebugEnabled())
- this.logger.debug("An authentication error has occurred. Returning the event id " + authEx.getType());
-
- return authEx.getType();
- }
-
- private boolean isCauseAuthenticationException(final TicketException e) {
- return e.getCause() != null && AuthenticationException.class.isAssignableFrom(e.getCause().getClass());
- }
-
- public final void setCentralAuthenticationService(final CentralAuthenticationService centralAuthenticationService) {
- this.centralAuthenticationService = centralAuthenticationService;
- }
-
-
- public final void setCredentialsBinder(final CredentialsBinder credentialsBinder) {
- this.credentialsBinder = credentialsBinder;
- }
-
- public final void setWarnCookieGenerator(final CookieGenerator warnCookieGenerator) {
- this.warnCookieGenerator = warnCookieGenerator;
- }
- }
ImageVaditeAuthenticationViaFormAction.java用到了另外一個類,也是咱們須要改造的類,改造的org.jasig.cas.authentication.principal.UsernamePasswordCredentials.java,你把源碼拿出來和這個類對比一下就知道只是增長了一個private String code;
CaptchaImageLoginCredentials.java
-
- package org.jasig.cas.authentication.handler;
-
- import java.util.Map;
-
- import javax.validation.constraints.NotNull;
- import javax.validation.constraints.Size;
-
- import org.jasig.cas.authentication.principal.RememberMeUsernamePasswordCredentials;
-
- public class CaptchaImageLoginCredentials extends RememberMeUsernamePasswordCredentials {
- private static final long serialVersionUID = 1L;
-
- private Map<String, Object> param;
-
-
- @NotNull
- @Size(min = 1, message = "驗證碼爲空")
- private String code;
-
- public String getCode() {
- return code;
- }
-
- public void setCode(String code) {
- this.code = code;
- }
-
- public Map<String, Object> getParam() {
- return param;
- }
-
- public void setParam(Map<String, Object> param) {
- this.param = param;
- }
- }
5.下面開始對xml文件進行修改:
1)仍是剛纔那個路徑,咱們以前修改的xml文件:C:\tomcat7\webapps\casServer\WEB-INF\cas-servlet.xml
- <!-- 修改這個bean,變成咱們本身的改造後的類
- <bean id="authenticationViaFormAction" class="org.jasig.cas.web.flow.AuthenticationViaFormAction"
- p:centralAuthenticationService-ref="centralAuthenticationService"
- p:warnCookieGenerator-ref="warnCookieGenerator"/>
- -->
-
- <bean id="authenticationViaFormAction" class="org.jasig.cas.authentication.handler.ImageVaditeAuthenticationViaFormAction"
- p:centralAuthenticationService-ref="centralAuthenticationService"
- p:warnCookieGenerator-ref="warnCookieGenerator"/>
-
2)C:\tomcat7\webapps\casServer\WEB-INF\login-webflow.xml
- <flow xmlns="http://www.springframework.org/schema/webflow"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/webflow
- http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
-
- <!-- 替換這個
- <var name="credentials" class="org.jasig.cas.authentication.principal.UsernamePasswordCredentials" />
- -->
- <var name="credentials" class="org.jasig.cas.authentication.handler.CaptchaImageLoginCredentials" />
-
-
-
- <on-start>
- <evaluate expression="initialFlowSetupAction" />
- </on-start>
找到節點:viewLoginForm
- <!-- 修改這個
- <view-state id="viewLoginForm" view="casLoginView" model="credentials">
- <binder>
- <binding property="username" />
- <binding property="password" />
- </binder>
- <on-entry>
- <set name="viewScope.commandName" value="'credentials'" />
- </on-entry>
- <transition on="submit" bind="true" validate="true" to="realSubmit">
- <evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" />
- </transition>
- </view-state>
- ->
-
- <view-state id="viewLoginForm" view="casLoginView" model="credentials">
- <binder>
- <binding property="username" />
- <binding property="password" />
- <binding property="code" />
-
- </binder>
- <on-entry>
- <set name="viewScope.commandName" value="'credentials'" />
- </on-entry>
- <transition on="submit" bind="true" validate="true" to="realSubmit">
- <evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" />
- </transition>
- </view-state>
其實你看到就是增長一個binding屬性code,方便注入到ImageVaditeAuthenticationViaFormAction這個類裏面。
文章末尾會粘貼全部xml文件,以及源碼下載地址
3)在C:\tomcat7\webapps\casServer\WEB-INF\classes最下面添加錯誤提示信息,因爲是使用unicode編碼,因此是看不懂的字符
login.code.tip=\u8BF7\u8F93\u5165\u9A8C\u8BC1\u7801
login.code.error=\u9A8C\u8BC1\u7801\u8F93\u5165\u6709\u8BEF
其實這兩行的意思以下:
login.code.tip=請輸入驗證碼
login.code.error=驗證碼輸入有誤
4)C:\tomcat7\webapps\casServer\WEB-INF\web.xml下新增對URL的處理
- <servlet-mapping>
- <servlet-name>cas</servlet-name>
- <url-pattern>/captcha.htm</url-pattern>
- </servlet-mapping>
這一步很重要,不然首頁打開時,根本找不到captacha.htm而不顯示圖片,我作這個的時候,也是搞了很久,才發現web.xml這麼重要的配置忘記寫。
5)如今去找你的前臺頁面C:\tomcat7\webapps\casServer\WEB-INF\view\jsp\default\ui\casLoginView.jsp,給加上驗證碼的文本框和響應事件吧,好比說看不清楚換一張
- <div class="row fl-controls-left">
- <label for="code" class="fl-label">驗證碼:</label>
-
- <script type="text/javascript">
- function refresh(){
- fm1.vali.src="";
- fm1.vali.src="captcha.htm";
- //img.src='captcha.htm?t='+new Date().getTime()
- }
- </script>
- <input class="required" type="text" tabindex="3" id="code" size="10" name="code" autocomplete="off" style="float:left;"/>
-
- <div style="height:30px;width:150px;text-align:center;margin-left:5px; float:left;vertical-align:middle; display: table-cell;">
- <a href="javascript:refresh();" onclick="refresh();" style="width:130px;height:30px;">
-
- <span style="display: block;float:left;width:60px;height:25px;float:left;">
- <img id="vali" width="60" height="30" src="captcha.htm" style="padding-left: 5px;"/>
- </span>
- <span style="display:block;width:60px;height:100%;float:left;vertical-align:middle; display: table-cell;margin-left:15px;">看不清楚?換一個</span>
- </a>
-
- </div>
ok 大功告成,編譯完的class這幾個文件,通通放入你的server端的各個指定路徑下,重啓tomcat,回帖感謝各位百度前輩吧。
文中所涉及的xml文件完整版:
下載地址:http://pan.baidu.com/share/link?shareid=439449164&uk=436295647