前言

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

技术原理

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){// 登录校验JSONObject  resultJson = 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.powernetwork.permission.common;import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.logging.Log;
import org.apache.commons.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:2017年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实现的单点登录可参考:http://blog.csdn.net/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:2017年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

JavaWeb简单的单点登录、验证码校验功能实现相关推荐

  1. php 单点登录实现代码,PHP简单实现单点登录功能示例

    1.准备两个虚拟域名 127.0.0.1  www.openpoor.com 127.0.0.1  www.myspace.com 2.在openpoor的根目录下创建以下文件 index.PHP 1 ...

  2. PHP简单实现单点登录功能示例

    1.准备两个虚拟域名 127.0.0.1  www.openpoor.com 127.0.0.1  www.myspace.com 2.在openpoor的根目录下创建以下文件 index.PHP 1 ...

  3. SpringBoot+Vue项目中实现登录验证码校验

    SpringBoot+Vue项目中实现登录验证码校验 在各大项目中,为保证数据的安全性,通常在登录页面加入验证码校验,以防止爬虫带来的数据泄露危机.本文将介绍在前后端分离的项目中,怎样实现图形验证码校 ...

  4. Java实现简单的单点登录

    摘要:单点登录(SSO)的技术被越来越广泛地运用到各个领域的软件系统当中.本文从业务的角度分析了单点登录的需求和应用领域:从技术本身的角度分析了单点登录技术的内部机制和实现手段,并且给出Web-SSO ...

  5. 单点登录原理和java实现简单的单点登录

    摘要:单点登录(SSO)的技术被越来越广泛地运用到各个领域的软件系统当中.本文从业务的角度分析了单点登录的需求和应用领域:从技术本身的角度分析了单点登录技术的内部机制和实现手段,并且给出Web-SSO ...

  6. Java用户注册手机短信验证码校验功能实现

    验证用户提交的手机短信验证码,如果验证码错误就跳回到当前页面.在短信验证码未填写或未正确填写时,就关闭底下注册按钮的功能,只有短信验证码通过校验后才打开注册按钮的功能.第二种方式是所有输入项全部填写完 ...

  7. JavaWeb跨域单点登录

    B/S架构前后端分离项目实现跨域单点登录方案设计 项目需求: 1.前后端分离项目,由后端实现会话管理,同时校验用户权限: 2.多个项目单点登录,允许跨域访问: 3.预留CS架构客户端点击按钮打开浏览器 ...

  8. loginrequired注解_简单实现一个登录验证的注解来保护私有资源

    背景 自定义注解标注受保护的资源访问,当要访问的url被标注了@LoginRequied的时候就变成了一个受保护的资源,需要用户登录或者更进一步需要用户拥有某个权限才能操作.本项目使用的springb ...

  9. JavaWeb 实验 Servlet用户登录验证

    实验2.2 Servlet用户登录验证 实验内容: 编写JSP程序,实现用户提交登录表单给Servlet,由Servlet 查询数据库(模拟查询,不用真的连接数据库查询),对用户是否存在进行验证. 实 ...

最新文章

  1. Java-----applet小程序简介
  2. 小编教您Springboot项目中异常拦截设计与处理
  3. DSP中LOG_printf()和printf()区别
  4. jde多目标_华科开源多目标跟踪(MOT)实时新SOTA:FairMOT
  5. 组件注册——@ComponentScan自动扫描组件指定扫描规则
  6. 计算机专业需要转正定级吗,全日制本科考进事业单位,没有取得初级资格职称,转正后能直接聘用为专业技术十二级岗位吗?...
  7. 利用cookies让sweetalert只出现一次
  8. mysql使用游标删除数据库_mysql 使用游标进行删除操作的存储过程
  9. 【Kafka】Kafka使用代码设置offset值
  10. H.264视频质量评价算法(基于偏最小二乘法回归)
  11. javaweb体育赛事网上售票系统
  12. 线性链表头插法,插入,删除操作(完整代码)
  13. 2020最新5Sing音乐解析解析接口 简单实用
  14. Unity脚本组件勾选框的存在的意义
  15. 幼麟棋牌技术分享系列:H5棋牌游戏加载速度优化
  16. 51单片机数字时钟套件 DIY散件
  17. RHCE7-NOTE(红帽工程师--题库详细笔记)
  18. 研华PCI板卡开发(5)快速入门(5)群组操作
  19. 爱马仕官方网站官方网站
  20. SQL语句查询不同年龄段人数

热门文章

  1. 【微信小程序】简单实现QQ发说说选择图片并显示功能
  2. 深入分析中小型千兆网吧解决方案(转)
  3. panda开始python的数据科学
  4. H.264与AVS视频标准核心技术比较
  5. 微信 android 平台 应用签名错误,详解IOS微信上Vue单页面应用JSSDK签名失败解决方案...
  6. 用opencv简单创建单色图片并保存
  7. 180828 逆向-网鼎杯(3-2)
  8. 边吃烧烤边喝啤酒引发疾病
  9. 数据存储单位的换算单位
  10. java中日期加上特定的天数或者时间