1:什么是单点登录?
答:单点登录的英文名叫做:Single Sign On(简称SSO)
一般我们的模块都是在同一个系统下,同一个tomcat(如图,以商城为例)
后来为了维护和资源我们把一个系统拆成多个子系统。
而单点登录就是其中的一部分。
我们有多个系统,每个系统都要输入一次账号和密码的话就会变得很麻烦,这时候就需要单点登录,只要其中一个子系统登录的话,其他系统都能自动登录。最为熟悉的例子就是淘宝和天猫,如果你淘宝登录后,打开天猫就能自动登录无需再输入账号和密码。
2:实现单点登录的思路(整个页面的流程)
假设两个页面
用户A系统没登陆,B系统没登陆
这时用户在A登陆,A生成token令牌存入cookie,redis存入已经登录参数
然后用户打开B系统登录页面,B系统登录页面发送请求,后端通过cookie获取到用户在A系统登录的信息
判断获取到的信息没有错误进行自动登陆
3:Demo代码(两个页面的代码是一样的,路径什么的改改就行了)
简单的登陆jq,ajax请求
前端
<body background="jquery/loginbg.jpg"> <div> <form style="margin: auto; width:230px" class="form-signin" > <h2 class="form-signin-heading"><font color="white">SSO1用户登录</font></h2> <!-- <label>账号:</label> --> <input type="text" id="txtUsername" class="form-control" name="username" placeholder="请输入账号" /><br/> <!-- <label>密码:</label> --> <input type="password" id="txtPassword" class="form-control" name="password" placeholder="请输入密码" /><br/> <!-- <input type="submit" value="提交" /> --> <a class="btn btn-primary btn-block" id="tijiao">提交</a><br> <!-- <button class="btn btn-primary btn-block" id="tijiao">提交</button><br> --> <button class="btn btn-primary btn-block" >重置</button><br> <!-- <input type="reset" value="重置" /> --> <input type="button" class="btn btn-primary btn-block" value="注册" onclick="window.location.href='add.jsp';"/> </div> <div id="chartmain" style="width:600px; height: 400px; margin: auto; " class="form-signin"></div> </body> <script type="text/javascript"> $("#tijiao").click(function(){ var paramMap = {}; paramMap.username = $("#txtUsername").val(); paramMap.userpasswd = $("#txtPassword").val(); $.ajax({ type:'POST', data:JSON.stringify(paramMap), dataType:'JSON', url:"user/slogin", contentType :"application/json;charset=UTF-8", async: true, error:function(jqXHR){ alert("发生错误:"+ jqXHR.status); }, success:function(data){ if(data){ if(data.state == "success"){ window.location.href ='index.jsp'; }else if(data.state == "fault"){ window.location.href ='login.jsp'; } } } }); }) window.onload = function(){ var paramMap = {}; var i = 0; paramMap.username = $("#txtUsername").val(); paramMap.userpasswd = $("#txtPassword").val(); $.ajax({ type:'POST', data:JSON.stringify(paramMap), dataType:'JSON', url:"user/slogin", // xhrFields: { // withCredentials: true // 携带跨域cookie // }, contentType :"application/json;charset=UTF-8", async: true, error:function(jqXHR){ alert("发生错误:"+ jqXHR.status); }, success:function(data){ if(data){ if(data.state == "success"){ window.location.href ='index.jsp'; }else if(data.state == "fault"){ debugger; var str=location.href; //取得整个地址栏 var num=str.indexOf("=") str=str.substr(num+1); if(str!="1"||str==null){ window.location.href ='login.jsp?state=1'; } } } } }); } </script>
后端
/** * 登陆 * @param <Account> * @param model * @param session * @return * @throws Exception */ @ResponseBody @RequestMapping(value = "/slogin", method = RequestMethod.POST) public ResultInfo slogin(@RequestBody Map<String, String> param, HttpSession session, HttpServletRequest request, ServletResponse response, HttpServletResponse responses) throws Exception { ResultInfo resultinfo = new ResultInfo(); /** * 判断redis是否连接成功 */ //连接本地的 Redis 服务 @SuppressWarnings("resource") Jedis jedis = new Jedis("localhost"); System.out.println("连接成功"); //用户验证 String username = param.get("username"); String passwd = param.get("userpasswd"); if(jedis.exists("islogin")){ //判断是否已经登录 if(!jedis.get("islogin").equals("1")){ // TODO: handle exception resultinfo.setState(StateType.fault); jedis.set("islogin", "0"); } }else if(!jedis.exists("islogin") && username.length()==0 && passwd.length()==0){ resultinfo.setState(StateType.fault); return resultinfo; } /** * 从cookie中获取数据 */ Cookie[] cookies = request.getCookies(); System.out.println(cookies); String cookievalue = null; for(Cookie cookiexs : cookies){ if(cookiexs.getName().equals("token")){ cookievalue = cookiexs.getValue(); break; } } if(cookievalue!=null){ //base64解密 String decusername = null; String decpasswd = null; int a = 1; byte[] decoded = Base64Utils.decode(cookievalue.getBytes()); String decodeStr = new String(decoded,"UTF-8"); System.out.println("Base 64 解密后:" + decodeStr); //获取用户名和密码 for(int i=-1; i<=decodeStr.lastIndexOf("=");++i){ i=decodeStr.indexOf("=",i); System.out.print(i+"\t"); if(a==1){ decusername = decodeStr.substring(i, i); a++; }else if(a>1){ decusername = decodeStr.substring(5,i-6); decpasswd = decodeStr.substring(i+1, decodeStr.length()-6); a=1; } System.out.println("账号为:"+decusername+"\t"+"密码为:"+decpasswd); } username = decusername; passwd = decpasswd; } try { if(username != "" && passwd !=""){ User user = userService.loginUsername(username); if(user ==null){ resultinfo.setState(StateType.fault); jedis.set("islogin", "0"); return resultinfo; }else if(!user.getPassword().equals(passwd)){ resultinfo.setState(StateType.fault); jedis.set("islogin", "0"); return resultinfo; } //设置token String token = tokenset(user); //将数据保存到cookie中 Cookie cookie = new Cookie("token", token); //cookie.setMaxAge(600); responses.addCookie(cookie); //将token发送给客户端,附带本次全局会话的sessionId //String allSessionId=request.getSession().getId(); //获取sessionid String sessionid = session.getId(); //设置状态(通过session判断该浏览器与认证中心的全局会话是否已经建立),生成令牌 //判断用户是否登录 request.getSession().setAttribute("isLogin", username); Map<String, String> tosession = new HashMap<String, String>(); tosession.put("sessionid", sessionid); jedis.set("islogin", "1"); jedis.set(token,username+passwd); jedis.expire("islogin", 120); // jedis.expire("token", 600); resultinfo.setData(token); resultinfo.setState(StateType.success); } if(jedis.get("islogin").equals("1")){ resultinfo.setState(StateType.success); }else{ resultinfo.setState(StateType.fault); } } catch (Exception e) { // TODO: handle exception resultinfo.setState(StateType.fault); resultinfo.setData(e.toString()); } return resultinfo; }
/** * 设置token */ private String tokenset(User user) { // TODO Auto-generated method stub String token = null; String sign = "hitomi"; String param = "name="+user.getUsername()+"passwd="+user.getPassword()+sign; token = Base64Utils.encodeToString(param.getBytes()); return token; }
此代码只是简单的实现单点登录的思路和功能,仅供参考