cas server 基础 数据库 验证码实现及其配置
2016-07-15 12:27
411 查看
由于需要从业务上将系统拆分成多个独立的子系统,所以需要sso。这里主要是讲述一下server 端的配置.
下面按照几个步骤进行描述
下载cas-server-4.1.9 (https://github.com/apereo/cas)
构建 server (maven)工程。
目录结构
基本配置
验证码配置
1、下载
2、构建工程(如果是直接下载源码 跳过这个步骤)
3、目录结构
resource/services 的json 文件是配置那些服务允许访问cas 的。如果这里没有配置,那么可能会在其他工程跳转到cas 登录的时候出现不被允许的错误。
resouces/messages.properties 国际化配置。
WEB-INF/spring-configuration 一些基础的配置。一般不需要去修改
WEB-INF/view 文件页面存放目录
WEB-INF/webflow 工作流的配置文件
WEB-INF/cas.properties 基础属性的配置文件在有些xml 可以在看${xxxx:yyy} xxxx 就是里面的配置文件
WEB-INF/web.xml
WEB-INF/deployerConfigContext.xml 这个是部署的配置文件,主要修改的也就是这个文件
WEB-INF/cas-servlet.xml cas 主要是使用的spring mvc security webflow , 这个就是springmvc 配置文件
4、基础配置
很多教程都是一来就介绍怎么配置https 这里先不进行ssl 配置,使用http
cookie 配置 默认使用https 的方式,如果使用http 将不会创建全局的cookie
数据库认证配置
==QueryDatabaseAuthenticationHandler可以自己实现,根据业务的需要==
3、允许使用cas 认证的服务配置。
默认的配置是用是json 的格式进行配置 resource/services 文件中,但是修改起来难度比较大, 所以这里使用xml 的配置
5.验证码配置
下面按照几个步骤进行描述
下载cas-server-4.1.9 (https://github.com/apereo/cas)
构建 server (maven)工程。
目录结构
基本配置
验证码配置
1、下载
在 https://github.com/apereo/cas 可以下载cas-server 的源代码 也可以在直接使用maven 进行构建。 如果是下载源码,那么复制里面的工程(cas-server-webapp)也是一样的
2、构建工程(如果是直接下载源码 跳过这个步骤)
1、创建一个maven 工程, 后面附上 依赖文件。 2、复制从github 下载的 cas-server-webapp 中 src/main/webapp 内容 到 webapp 中,并且将resources 中的文件复制到 resources 中,目的是减少配置。 这两个文件夹中主要是配置文件。不要遗漏。
pom.xml 文件。 <properties> <spring.version>3.2.6.RELEASE</spring.version> <cas-server.version>4.1.9</cas-server.version> </properties> <dependencies> <dependency> <groupId>org.jasig.cas</groupId> <artifactId>cas-server-webapp-support</artifactId> <version>${cas-server.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>org.jasig.cas</groupId> <artifactId>cas-server-security-filter</artifactId> <version>2.0.4</version> </dependency> <dependency> <groupId>org.jasig.cas</groupId> <artifactId>cas-server-support-jdbc</artifactId> <version>${cas-server.version}</version> </dependency> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>11.2.0.3</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.22</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope> 4000 provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.1.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.1.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.1.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>4.1.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.1.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.1.8.RELEASE</version> </dependency> <dependency> <groupId>com.ryantenney.metrics</groupId> <artifactId>metrics-spring</artifactId> <version>3.0.1</version> </dependency> </dependencies>
3、目录结构
resource/services 的json 文件是配置那些服务允许访问cas 的。如果这里没有配置,那么可能会在其他工程跳转到cas 登录的时候出现不被允许的错误。
resouces/messages.properties 国际化配置。
WEB-INF/spring-configuration 一些基础的配置。一般不需要去修改
WEB-INF/view 文件页面存放目录
WEB-INF/webflow 工作流的配置文件
WEB-INF/cas.properties 基础属性的配置文件在有些xml 可以在看${xxxx:yyy} xxxx 就是里面的配置文件
WEB-INF/web.xml
WEB-INF/deployerConfigContext.xml 这个是部署的配置文件,主要修改的也就是这个文件
WEB-INF/cas-servlet.xml cas 主要是使用的spring mvc security webflow , 这个就是springmvc 配置文件
4、基础配置
很多教程都是一来就介绍怎么配置https 这里先不进行ssl 配置,使用http
cookie 配置 默认使用https 的方式,如果使用http 将不会创建全局的cookie
WEB-INF/spring-configuration/ticketGrantingTicketCookieGenerator.xml <!-- TODO 这里将 cookieSecure 修改为了false ,目的是使用http --> <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/cas-servlet.xml
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver" p:defaultLocale="zh_CN" />
- 认证处理配置 WEB-INF/deployerConfigContext.xml
<!-- TODO 这里设置 p:requireSecure="false" 目的是为了使用http --> <bean id="proxyAuthenticationHandler" class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler" p:requireSecure="false" p:httpClient-ref="supportsTrustStoreSslSocketFactoryHttpClient" />
这样http 就配置完成了! 可以进行测试一下了
数据库认证配置
<!-- 加密方式配置 --> <bean id="MD5PasswordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder"> <constructor-arg index="0" value="MD5" /> </bean> <!-- Oracle connector --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /> <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:ytym" /> <property name="username" value="xxx" /> <property name="password" value="xxx" /> </bean> <!-- 使用自定义的查询方式验证用户信息 --> <bean id="primaryAuthenticationHandler" class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"> <property name="dataSource" ref="dataSource" /> <property name="passwordEncoder" ref="MD5PasswordEncoder"/> <property name="sql" value="select login_pass from user where name = ? " /> </bean>
==QueryDatabaseAuthenticationHandler可以自己实现,根据业务的需要==
3、允许使用cas 认证的服务配置。
默认的配置是用是json 的格式进行配置 resource/services 文件中,但是修改起来难度比较大, 所以这里使用xml 的配置
找到 WEB-INF/deployerConfigContext.xml 中的 serviceRegistryDao 进行修改
<!-- 这里注释掉, 使用xml 的配置 方式 --> <bean id="serviceRegistryDao" class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl" p:registeredServices-ref="registeredServicesList" /> <util:list id="registeredServicesList"> <!--<bean class="org.jasig.cas.services.RegexRegisteredService">--> <!--<property name="id" value="10000001"/>--> <!--<property name="name" value="HTTPS and IMAPS"/>--> <!--<property name="description" value="This service definition authorized all application urls that support HTTPS and IMAPS protocols."/>--> <!--<property name="serviceId" value="^(https|imaps)://.*"/>--> <!--<property name="evaluationOrder" value="10000001"/>--> <!--</bean>--> <bean class="org.jasig.cas.services.RegexRegisteredService"> <property name="id" value="10000002"/> <property name="name" value="localhost Test"/> <property name="description" value="local server config"/> <property name="serviceId" value="^(http?|https?|imaps?):/ f7fa /((127\.0\.0\.1)|(localhost)|(test.com))(:[\d]+)?/.*"/> <property name="evaluationOrder" value="10000002"/> </bean> <bean class="org.jasig.cas.services.RegexRegisteredService"> <property name="id" value="10000003"/> <property name="name" value="ydzx online website"/> <property name="description" value="ydzx online"/> <property name="serviceId" value="^(http?|https?|imaps?)://[\w]+.ydzxlm.com/.*"/> <property name="evaluationOrder" value="10000002"/> </bean> </util:list>
5.验证码配置
自己写验证码的实现,并且写好验证码验证的接口 实现可以见后面的代码 1、在 配置验证bean
WEB-INF/cas-servlet.xml <!-- 验证码验证 验证码超时时间,默认是五分钟 --> <bean id="authCodeValidateFormAction" class="com.ydzx.cas.server.web.flow.AuthCodeValidateFormAction" />
2、配置登录流程
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"/> </binder> <on-entry> <set name="viewScope.commandName" value="'credential'"/> <!-- <evaluate expression="samlMetadataUIParserAction" /> --> </on-entry> <!--<transition on="submit" bind="true" validate="true" to="realSubmit"/>--> <!-- 修改,目的是在登录的时候,加上验证码的验证 --> <transition on="submit" bind="true" validate="true" to="authCodeValidate"/> </view-state> <!-- 添加一个新的流程,在登录前添加验证码 --> <action-state id="authCodeValidate" > <evaluate expression="authCodeValidateFormAction.validate(flowRequestContext,flowScope.credential, messageContext)" /> <transition on="success" to="realSubmit" /> <transition on="error" to="generateLoginTicket" /> </action-state>
验证码 相关代码
验证码实现类 : VerfiyCode.java public class VerfiyCode { private String randomCode; public VerfiyCode() { System.setProperty("java.awt.headless", "true"); } 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 BufferedImage getImage() { // 在内存中创建图象 int width = 60, height = 20; BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // 获取图形上下 Graphics g = image.getGraphics(); // 生成随机 Random random = new Random(); // 设定背景 g.setColor(getRandColor(200, 250)); g.fillRect(0, 0, width, height); // 设定字体 g.setFont(new Font("Times New Roman", Font.PLAIN, 18)); // 画边 g.setColor(new Color(255, 255, 255)); g.drawRect(0, 0, width - 1, height - 1); // 随机产生155条干扰线,使图象中的认证码不易被其它程序探测 g.setColor(getRandColor(160, 200)); for (int i = 0; i < 155; i++) { int x = random.nextInt(width); int y = random.nextInt(height); int xl = random.nextInt(12); int yl = random.nextInt(12); g.drawLine(x, y, x + xl, y + yl); } // 取随机产生的认证 (4位数 ) String sRand = ""; for (int i = 0; i < 4; i++) { String rand = String.valueOf(random.nextInt(10)); sRand += rand; // 将认证码显示到图象中 g.setColor(new Color(20 + random.nextInt(110), 20 + random .nextInt(110), 20 + random.nextInt(110))); // 调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生 g.drawString(rand, 13 * i + 6, 16); } // 将认证码存入 this.setRandomCode(sRand); // session.setAttribute("rand",sRand); // 图象生效 g.dispose(); // 输出图象到页 return image; } /** * 随机数 */ public String getRandomCode() { return this.randomCode; } public void setRandomCode(String randomCode) { this.randomCode = randomCode; } }
AuthCodeValidateFormAction.java 验证码验证实现 public class AuthCodeValidateFormAction { protected final Logger logger = LoggerFactory.getLogger(getClass()); private long outTime = 5*60*1000; public static final String SUCCESS = "success"; public static final String ERROR = "error"; public Event validate(final RequestContext context, final Credential credential, final MessageContext messageContext) { try { HttpServletRequest request = WebUtils.getHttpServletRequest(context); String image_code = (String) request.getSession().getAttribute("image_no"); Long image_create_time = (Long) request.getSession().getAttribute("image_create_time"); if( (image_create_time != null && Math.abs(System.currentTimeMillis() - image_create_time) > outTime) || (image_code == null) ){ resultMsgWrapper(messageContext,"验证码超时!"); return new Event(this, ERROR); } String username = request.getParameter("username"); if (username == null) { resultMsgWrapper(messageContext,"用户信息不能为空!"); return new Event(this, ERROR); } String[] separator_chars = username.split("#@#"); if(separator_chars.length < 2){ resultMsgWrapper(messageContext,"信息不合法!"); return new Event(this, ERROR); } if(separator_chars[1] == null && StringUtils.isEmpty(separator_chars[1])){ resultMsgWrapper(messageContext,"验证码不能为空!"); return new Event(this, ERROR); } if (image_code != null && image_code.trim().equals(separator_chars[1])) { request.getSession().removeAttribute("image_no"); } else { resultMsgWrapper(messageContext,"验证码信息错误!"); return new Event(this, ERROR); } return newEvent(SUCCESS); } catch (final Exception e) { logger.debug(e.getMessage(), e); return newEvent(ERROR, e); } } private void resultMsgWrapper(MessageContext messageContext,String msg) { MessageBuilder msgBuilder = new MessageBuilder(); msgBuilder.defaultText(msg); messageContext.addMessage(msgBuilder.error().build()); } /** * New event based on the given id. * * @param id the id * @return the event */ private Event newEvent(final String id) { return new Event(this, id); } /** * New event based on the id, which contains an error attribute referring to the exception occurred. * * @param id the id * @param error the error * @return the event */ private Event newEvent(final String id, final Exception error) { return new Event(this, id, new LocalAttributeMap("error", error)); } public long getOutTime() { return outTime; } public void setOutTime(long outTime) { this.outTime = outTime; } }
verifyCode.jsp 实现。 <%@ page language="java" contentType="image/jpeg" pageEncoding="UTF-8" import="VerfiyCode,javax.imageio.ImageIO, javax.servlet.ServletContext,org.springframework.web.context.support.WebApplicationContextUtils,org.springframework.context.ApplicationContext"%> <% try { //设置页面不缓存 response.setHeader("Pragma", "No-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); response.reset(); VerfiyCode verfiyCode = new VerfiyCode(); ImageIO.write(verfiyCode.getImage(), "JPEG", response.getOutputStream()); //存放会话中 session.setAttribute("image_no", verfiyCode.getRandomCode()); session.setAttribute("image_create_time", System.currentTimeMillis()); ServletContext servletContext = config.getServletContext(); // ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext); // Cache verifyCodeCache = (Cache)applicationContext.getBean("verifyCodeCache"); // Element element = new Element(verfiyCode.getRandomCode(), ""); // verifyCodeCache.put(element); out.clear(); out = pageContext.pushBody(); } catch (Exception e) { System.out.println(e); } %>
login.html 登录页面(WEB-INF/view/jsp/default/ui/casLoginView.jsp)(不能直接使用 只表达基础的意思) <form action ="login" id="fm1" > <input type="hidden" name="lt" value="${loginTicket}" /> <input type="hidden" name="execution" value="${flowExecutionKey}" /> <input type="hidden" name="_eventId" value="submit" /> <input class="input1" type="hidden" id="username" path="username" autocomplete="off" htmlEscape="true" /> <table> <tr> <td>用户名</td> <td><input name="name"></td> </tr> <tr> <td>密码</td> <td><password class="input1" id="password" tabindex="2" path="password" htmlEscape="true" autocomplete="off" /></td> </tr> <tr> <td>验证码</td> <td> <input name="name"> <img id="imgValidateCode" src="<%=request.getContextPath()%>/verifyCode.jsp?rd=1" /> </td> </tr> <Tr> <Td> <button onclick="checkUser" >登录</button> </tr> </table> </form> <script> function checkUser(){ $("#username").val($ $("#name").val() + "#@#" + $("#image_no").val() ); $("#fm1").submit(); } </script>
相关文章推荐
- Android之获取手机上的图片和视频缩略图thumbnails
- maven学习
- 数据库链接字符串查询网站
- maven插件maven-war-plugin的使用
- jenkins------部署项目到jboss eap下
- java自动生成验证码插件-kaptcha
- maven使用经验集
- Seafile Server本地权限提升漏洞(CVE-2014-5443)
- 从USB安装Ubuntu Server 10.04.3 图文详解
- DB2实例管理
- DB2实例管理
- 使用zabbix监控Nginx活动状态--Part1
- 保障MySQL数据安全的14个最佳方法
- 高效访问Internet-启用ISA Server的缓存
- mysql问答汇集
- 第三章 数据库备份和还原
- windows server域用户提升到本地更高权限组中的方法
- 创建一个空的IBM DB2 ECO数据库的方法
- Access 2000 数据库 80 万记录通用快速分页类