项目跳转之免登录

文章介绍

项目A跳转至项目B,项目A在以登录的情况下,登录项目B时还需要输入项目B的帐号,用户体验不好。因此需要将两个项目绑定,项目A登陆后向项目B跳转时可直接登录。本项目是维护别人的老系统,是使用jsp开发的,虽然用的技术比较老,但是整个流程的思想还是挺不错的。

业务流程分析

  1. 项目A向项目B跳转时,携带ticket
  2. 项目B获取到ticket后,解析出用户信息
  3. 根据用户信息判断数据库中是否存在该用户,若存在,返回前端可直接登录项目B状态。不存则插入,错误则返回前端不可直接登录项目B状态
  4. 使用session存用户状态,因为是jsp项目,使用技术比较老。
  5. 前端根据状态进行跳转,成功则重定向系统主页,失败则停留在登录页。

获取ticket并解析

项目A-项目B,原系统是跳转到登录页,在这里我封装了一个方法,当项目B登录页加载时,调用后端解析ticket的方法。

获取ticket后,将appid,secret,ticket三者经MD5
加密后形成signature,之后调用第三方接口获取用户的信息。
注意:
参数在路径上进行传递时,可能会被转义。我们通过getParameter()方法获取真实的参数,用于md5加密。
使用getQueryString()方法获取未被解析的参数,进行第三方接口的访问。

校验ticket接口

 @ResponseBody
    @RequestMapping(value = "/login/verify", method = {
    
    RequestMethod.GET})
    public boolean verifySignature(HttpServletRequest request) throws UnsupportedEncodingException, NoSuchAlgorithmException {
    
    
       logger.info("校验signature");
        String ticket = request.getParameter("ticket").replace("ticket=", "");
        String secret = "2nN5Dd+Ehz9mJ06sb7+GpvNNyI01Fzr9k7XLmd+imu4=";
        String appId = "104203";
        String pass = ticket + appId + secret;
        String signature = encodeMd5(pass);
        //TODO 调用第三方
        String url = "http://www.ilab-x.com/open/api/v2/token?" +
                "ticket=" + request.getQueryString().replace("ticket=","") +
                "&appid=" + appId +
                "&signature=" + signature;
        System.out.println(url);
        JSONObject currentUserResult = sendRequest(url);
        JSONObject currentUserResult = sendRequest(url);
        String un = currentUserResult.getString("un");
        String dis = currentUserResult.getString("dis");
        String contextPath = request.getContextPath();
        //用户存在则返回用户,不存在返回null
        AdminEntity adminEntity = adminService.existAdminNameAndReturnAdmin(un);
        if (adminEntity != null) {
    
    
            httpSession.setAttribute("admin", adminEntity);
            return true;
        } else {
    
    
            //创建用户    密码默认为123456
            adminEntity = new AdminEntity();
            adminEntity.setNickname(un);
            adminEntity.setPhoneNumber("");
            adminEntity.setEmail("");
            adminEntity.setCompany("");
            adminEntity.setSex(1);
            adminEntity.setRole(1);
            adminEntity.setVisible(1);
            adminEntity.setPassword("123456");
            //数据库不存在进行插入
            int status = adminService.register(adminEntity);
            if (status > 0) {
    
    
                //免登录成功
                //通过session记录用户的登录状态
                httpSession.setAttribute("admin", adminEntity);
                return true;
            } else {
    
    
                return false;
            }
        }
    }

发送第三方请求封装

根据校验结果进行重定向跳转,如果校验成功,跳转B系统,校验失败,跳转B系统登录页。

    public JSONObject sendRequest(String url) {
    
    
        HttpURLConnection conn = null;
        try {
    
    
            URL serverUrl = new URL(url);
            conn = (HttpURLConnection) serverUrl.openConnection();
            conn.setRequestMethod("GET");
            //设置连接超时时间和读取超时时间
            conn.setConnectTimeout(15000);
            conn.setReadTimeout(60000);
            conn.setRequestProperty("Accept", "application/json");
            //必须设置false,否则会自动redirect到重定向后的地址
            conn.setInstanceFollowRedirects(false);
            //发送请求
            conn.connect();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
        //获取返回值
        return getHttpReturn(conn);
    }

    //获取请求返回值
    public JSONObject getHttpReturn(HttpURLConnection connection) {
    
    
        //将返回的输入流转换成字符串
        BufferedReader bufferedReader = null;
        InputStreamReader inputStreamReader = null;
        String result = "";
        try {
    
    
            if (200 == connection.getResponseCode()) {
    
    
                StringBuffer buffer = new StringBuffer();
                inputStreamReader = new InputStreamReader(connection.getInputStream(), "UTF-8");
                bufferedReader = new BufferedReader(inputStreamReader);
                String str = null;
                while ((str = bufferedReader.readLine()) != null) {
    
    
                    buffer.append(str);
                }
                result = buffer.toString();

            } else {
    
    
                System.out.println("ResponseCode is an error code:" + connection.getResponseCode());
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();

        } finally {
    
    
            try {
    
    
                if (inputStreamReader != null) {
    
    
                    inputStreamReader.close();
                }
                if (bufferedReader != null) {
    
    
                    bufferedReader.close();
                }

            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
            connection.disconnect();
        }
        JSONObject res = new JSONObject(result);
        logger.info("【获取signature】"+res);
        return res;
    }

MD5加密

32位大写加密

    public String encodeMd5(String pass) throws NoSuchAlgorithmException, UnsupportedEncodingException {
    
    
        //md5大写加密
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        md5.update((pass).getBytes("UTF-8"));
        byte b[] = md5.digest();
        int i;
        StringBuffer buf = new StringBuffer("");

        for (int offset = 0; offset < b.length; offset++) {
    
    
            i = b[offset];
            if (i < 0) {
    
    
                i += 256;
            }
            if (i < 16) {
    
    
                buf.append("0");
            }
            buf.append(Integer.toHexString(i));
        }
        return buf.toString().toUpperCase();
    }

前端页面跳转

其实最初的实现方案是校验和跳转是在一个接口中完成的,接口直接返回对应页面的字符串进行页面重定向,但是因为ajax不支持页面重定向,只支持页面刷新,这样虽然后端指明重定向,但是实际还是停留在原页面,因此使用了校验的页面分开的方式。

    window.onload = function () {
    
    
        var ticket = getUrlParams(window.location.href, "ticket");
        var basePath=$('#basePath').attr("value");
        var path=$('#path').attr("value");
        console.log("path"+path)
        console.log("bathPath"+basePath)
        if (ticket != null && ticket != "") {
    
    
            $.ajax({
    
    
                //校验target
                url: path+"/login/verify?ticket=" + ticket,
                type: "GET",//请求方式
                //参数设置
                // data:"username=tom&age=18",
                响应成功后的回调函数
                data: {
    
    },
                //请求成功
                success: function (data) {
    
    
                    console.log(data)
                    if (data == true) {
    
    
                        window.location.href = basePath+"/login/avoidLogin";
                    } else {
    
    
                        window.location.href = basePath;
                    }
                },
                //请求失败
                error: function () {
    
    
                    window.location.href = basePath;
                },
                //设置接收到的响应数据的格式
                dateType: "text"
            })
        }
    };

jsp中获取当前请求地址

<basePath value = "<%=path%>" id = "path"></basePath>
 var path=$('#path').attr("value");

jsp中获取当前请求路径

<basePath value = "<%=basePath%>" id = "basePath"></basePath>
 var basePath=$('#basePath').attr("value");

js获取当前url地址

window.location.href

js获取请求路径中的参数

     var ticket = getUrlParams(window.location.href, "ticket");
    function getUrlParams(url, name) {
    
    
        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)")
        const cuturl = url.substr(url.indexOf("?") + 1)
        const matchArray = cuturl.match(reg)
        if (matchArray) {
    
    
            return decodeURI(matchArray[2])
        }
        return null;
    };

验证成功后,免登录处理

因为再次请求接口时,我们使用的是js的重定向,并非发送的ajax请求,因此我们可以在后端通过返回字符串直接重定向到指定页面。

  @RequestMapping(value = "/login/avoidLogin", method = {
    
    RequestMethod.GET})
    public String avoidLogin(HttpServletRequest request, HttpServletResponse response, final RedirectAttributes redirectAttributes, Model model) throws Exception {
    
    
        logger.info("进行免登录");
            AdminEntity admin = (AdminEntity) httpSession.getAttribute("admin");
            String contextPath = request.getContextPath();
            if (admin != null) {
    
    
                //登陆成功,跳转到首页。
                redirectAttributes.addFlashAttribute("css", "success");
                redirectAttributes.addFlashAttribute("msg", "登录成功!");
                if (admin.getRole() == Constants.USER) {
    
    //普通用户
                    //model.addAttribute("to", "adminDetail");
                    model.addAttribute("to", "myproject");

                } else if (admin.getRole() == Constants.SUPERADMIN || admin.getRole() == Constants.ADMIN) {
    
    //普通管理员、系统管理员
                    //model.addAttribute("to", "adminList");
                    model.addAttribute("to", "myproject");
                }
                return "manager/index";//跳转到后台首页
            } else {
    
    
                if (LoginInterceptor.verifyCert(request) == false) {
    
    
                    System.out.println("certFlag: 证书无效");
                    response.sendRedirect(contextPath + "/cert.jsp");
                } else {
    
    
                    System.out.println("certFlag: 证书有效");
                }
                return "manager/homepage";
            }

//        }
    }

Guess you like

Origin blog.csdn.net/zhang19903848257/article/details/120479260