700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > JavaWeb简单的单点登录 验证码校验功能实现

JavaWeb简单的单点登录 验证码校验功能实现

时间:2024-07-31 04:59:27

相关推荐

JavaWeb简单的单点登录 验证码校验功能实现

前言

最近项目刚刚告一段落,后期有时间会慢慢分解整理出来给大家分享。本文主要提供思路和核心代码,建立在有一定后台基础读者上。(相信没有基础的同学只要认真细读也是可以理解的)

技术原理

1、单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。 现实中举个栗子:颐和园是北京著名的旅游景点。在颐和园内部有许多独立的景点,例如“苏州街”、“佛香阁”和“德和园”,都可以在各个景点门口单独买票。很多游客需要游玩所有的景点,这种买票方式很不方便,需要在每个景点门口排队买票,钱包拿进拿出的,容易丢失,很不安全。于是绝大多数游客选择在大门口买一张通票(也叫套票),就可以玩遍所有的景点而不需要重新再买票。他们只需要在每个景点门 口出示一下刚才买的套票就能够被允许进入每个独立的景点。

单点登录也一样,当用户第一次访问应用系统的时候,因为还没有登录,会被引导到认证系统中进行登录;根据用户提供的登录信息,认证系统进行身份效验(eg:用户名、密码、验证码校验),如果通过校验,应该返回给用户一个认证的凭据--ticket;用户再访问应用其他模块就会将这个ticket带上,作为自己认证的凭据,应用系统接受到请求之后会把ticket送到认证系统进行效验(页面拦截器校验),检查ticket的合法性。如果通过效验,用户就可以在不用再次登录的情况下访问。 笔者代码实现机制:建立用户表SYS_USER存放用户名、密码、用户id等字段,用到的唯一认证凭据ticket指的是:用户名(loginName)、用户id(userId),用户校验登录成功后,用session存储凭据,当用户切换界面时,通过拦截器LoginInterceptor校验用户是否带有认证凭据,从而实现单点登录。

2、验证码校验:加载登录首页时,通过Get方式获取后台生成的校验码,同时后台用session存储验证码(为后续检验做准备),当前台检测到用户填写完验证码时,触发机制,通过Get方式传参给后台匹配实现检验机制。

逻辑代码

1、单点登录

控制层LoginCtroller.java(result_code为0表示登录校验成功,session保存的就是用户认证凭据)

@RequestMapping(value ="login.do",method = {RequestMethod.POST})public @ResponseBody JSONObject login(@RequestBody JSONObject loginJson,HttpServletRequest request, HttpServletResponse response){// 登录校验JSONObjectresultJson = userService.login(loginJson);if (resultJson.getIntValue("result_code") == 0) {SysUser sysUser =(SysUser) resultJson.get("sysUser");// 创建登录Session信息resultJson.put("id", sysUser.getId());resultJson.put("name", sysUser.getName());resultJson.put("loginName", sysUser.getLoginName());this.initSession(request, sysUser);logger.info(String.format("用户:%s 登录系统,登录时间:%s", loginJson.getString("loginName")));} return resultJson;}private void initSession(HttpServletRequest request,SysUser sysUser) {//创建登录Session信息HttpSession httpSession = request.getSession();httpSession.setAttribute("loginName", sysUser.getLoginName());httpSession.setAttribute("userId", sysUser.getId());}

接口实现类UserServiceImpl.java(接口类UserService.java)中的登录校验方法,这里面主要是获取前台传递的用户信息参数,再通过用户名查询数据库用户信息,可能难点是用MD5密码加密核对信息进行校验。

public JSONObject login(JSONObject jSONObject){JSONObject resultJson = new JSONObject();try {if(StringUtils.isBlank( jSONObject.getString("loginName"))){throw new RuntimeException("登录用户名不能为空!");}if(StringUtils.isBlank( jSONObject.getString("password"))){throw new RuntimeException("登录必须填写密码!");}String loginName = jSONObject.getString("loginName");SysUser sysUser = sysUserMapper.findByLoginName(loginName);if(sysUser==null){throw new RuntimeException("用户不存在!");}if(StringUtils.isBlank(jSONObject.getString("password"))){throw new RuntimeException("登录密码不能为空!");}String password = MD5Util.getMD5String(jSONObject.getString("password"));if(StringUtils.isBlank(sysUser.getPassword()) || !sysUser.getPassword().equals((password))){throw new RuntimeException("密码错误!");}resultJson.put("result_code", 0);resultJson.put("result_detail", "success");resultJson.put("sysUser", sysUser);} catch (RuntimeException e){resultJson.put("result_code", -2);resultJson.put("result_detail", e.getMessage());logger.error("login ",e);}catch (Exception e){resultJson.put("result_code", -1);resultJson.put("result_detail", e.getMessage());logger.error("login ",e);}return resultJson;}

加密工具类MD5Util.java

package com.kilomob.mon;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import mons.logging.Log;import mons.logging.LogFactory;/*** * @author fengjk**/public class MD5Util {private static Log log = LogFactory.getLog(MD5Util.class);/*** 默认的密码字符串组合,apache校验下载的文件的正确性用的就是默认的这个组合*/protected static char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };protected static MessageDigest messagedigest = null;static {try {messagedigest = MessageDigest.getInstance("MD5");} catch (NoSuchAlgorithmException nsaex) {log.error(MD5Util.class.getName() + "初始化失败,MessageDigest不支持MD5Util。");nsaex.printStackTrace();}}public static String getMD5String(String str){if(str!=null){messagedigest.update(str.getBytes());return bufferToHex(messagedigest.digest());}else{return null;}}private static String bufferToHex(byte bytes[]) {return bufferToHex(bytes, 0, bytes.length);}private static String bufferToHex(byte bytes[], int m, int n) {StringBuffer stringbuffer = new StringBuffer(2 * n);int k = m + n;for (int l = m; l < k; l++) {appendHexPair(bytes[l], stringbuffer);}return stringbuffer.toString();}private static void appendHexPair(byte bt, StringBuffer stringbuffer) {char c0 = hexDigits[(bt & 0xf0) >> 4];char c1 = hexDigits[bt & 0xf];stringbuffer.append(c0);stringbuffer.append(c1);}}

拦截器配置applicationContext.xml

<!-- 类的存放路径classignoreUrlList和interceptro指的是忽略,不拦截--><bean id="loginInterceptor" class="com.kilomob.powernetwork.managerweb.interceptor.LoginInterceptor"><property name="loginPage" value="/login.html"></property><property name="ignoreUrlList"><list><value>/api/login.do</value><value>/login.html</value><value>/api/loginout.do</value><value>/api/loginValidate.do</value><value>/api/imgcode</value><value>/api/vali/imagecode</value></list></property></bean><mvc:interceptors><mvc:interceptor><mvc:mapping path="/**"/><mvc:exclude-mapping path="/api/imgcode"/><mvc:exclude-mapping path="/api/vali/imagecode"/><ref bean="loginInterceptor"/></mvc:interceptor></mvc:interceptors>

注意此处的loginPage和ignoreUrlList应与下面的拦截类变量名一致。

拦截类LoginInterceptor.java

package com.kilomob.powernetwork.managerweb.interceptor;import java.io.File;import java.util.List;import javax.annotation.Resource;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import com.kilomob.powernetwork.managerweb.util.WebConfig;/*** @Description:登录拦截器* @author: fengjk* @time:3月20日 下午8:11:25*/public class LoginInterceptor implements HandlerInterceptor {private String loginPage;private List<String> ignoreUrlList;public String getLoginPage() {return loginPage;}public void setLoginPage(String loginPage) {this.loginPage = loginPage;}public List<String> getIgnoreUrlList() {return ignoreUrlList;}public void setIgnoreUrlList(List<String> ignoreUrlList) {this.ignoreUrlList = ignoreUrlList;}@Overridepublic boolean preHandle(HttpServletRequest paramHttpServletRequest,HttpServletResponse paramHttpServletResponse, Object paramObject)throws Exception {paramHttpServletResponse.addHeader("P3P", "CP=CAO PSA OUR");String path = paramHttpServletRequest.getRequestURI();boolean ignore = false;for (String url : ignoreUrlList) {if (path.contains(url)) {ignore = true;break;}}if (ignore) {return true;}HttpSession httpSession = paramHttpServletRequest.getSession();if (httpSession.getAttribute("userId") == null && httpSession.getAttribute("loginName") == null) {paramHttpServletResponse.setContentType("text/html;charset=UTF-8");paramHttpServletResponse.sendRedirect("http://127.0.0.1:8080/managerweb/login.html");return false;}paramHttpServletRequest.setAttribute("loginName", httpSession.getAttribute("loginName"));paramHttpServletRequest.setAttribute("userId", httpSession.getAttribute("userId"));return true;}@Overridepublic void postHandle(HttpServletRequest paramHttpServletRequest,HttpServletResponse paramHttpServletResponse, Object paramObject,ModelAndView paramModelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest paramHttpServletRequest,HttpServletResponse paramHttpServletResponse, Object paramObject,Exception paramException) throws Exception {}}

通过session检验用户是否已经登录过,否的话则跳转回首页。关于CAS实现的单点登录可参考:/small_love/article/details/6664831/

2、验证码校验

控制层LoginCtroller.java

@RequestMapping(value ="/imgcode",method = {RequestMethod.GET})public void getImgCode(HttpServletRequest request,HttpServletResponse response) throws IOException {HttpSession session = request.getSession();session.removeAttribute("code");response.setContentType("image/jpeg");ServletOutputStream sos = response.getOutputStream();response.setHeader("Pragma", "No-cache");response.setHeader("Cache-Control", "no-cache");response.setDateHeader("Expires", 0);BufferedImage image = new BufferedImage(WIDTH, HEIGHT,BufferedImage.TYPE_INT_RGB);Graphics g = image.getGraphics();char[] rands = generateCheckCode();drawBackground(g);drawRands(g, rands);g.dispose();ByteArrayOutputStream bos = new ByteArrayOutputStream();ImageIO.write(image, "JPEG", bos);byte[] buf = bos.toByteArray();response.setContentLength(buf.length);sos.write(buf);bos.close();sos.close();session.setAttribute("code", new String(rands));}private void drawBackground(Graphics g) {g.setColor(new Color(72, 75, 83));g.fillRect(0, 0, WIDTH, HEIGHT);/*for (int i = 0; i < 120; i++) {int x = (int) (Math.random() * WIDTH);int y = (int) (Math.random() * HEIGHT);int red = (int) (Math.random() * 255);int green = (int) (Math.random() * 255);int blue = (int) (Math.random() * 255);g.setColor(new Color(red, green, blue));g.drawOval(x, y, 1, 0);}*/}private void drawRands(Graphics g, char[] rands) {g.setColor(new Color(0xe0e0e0));g.setFont(new Font("Arial", Font.BOLD | Font.ITALIC, 24));g.drawString("" + rands[0], 1, 27);g.drawString("" + rands[1], 19, 25);g.drawString("" + rands[2], 39, 27);g.drawString("" + rands[3], 58, 26);}private char[] generateCheckCode() {String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";char[] rands = new char[4];for (int i = 0; i < 4; i++) {int rand = (int) (Math.random() * 62);rands[i] = chars.charAt(rand);}return rands;}/*** @Description:校验验证码* @param imagecode* @param request* @param response* @return* boolean* @exception:* @author: fengjk* @time:3月27日 下午3:45:12*/@RequestMapping(value= "/vali/imagecode/{imagecode}" ,method = {RequestMethod.GET} )public int valideImage(@PathVariable(name = "imagecode") String imagecode,HttpServletRequest request,HttpServletResponse response) {HttpSession session = request.getSession();String code = (String)session.getAttribute("code");if(code != null && code.toUpperCase().equals(imagecode.toUpperCase())){return 0;}return 1;}

前台加载首页时通过Get方式请求getImgCode方法获取验证码,后台同时用session保存数据,当校验验证码时,通过valideImage方法校验,返回0说明校验成功。

总结

篇幅不长,相信读者在理解实现原理基础上回归代码会比较通俗易懂。文章如有误处和不足,请及时留言告知笔者,万分感谢!欢迎加群互相探讨学习,qq:583138104

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。