zoukankan      html  css  js  c++  java
  • 我的单点登录和退出思路

    参考:

    一、单点登录思路

      思路:①判断业务系统是否登录,如果已登录就直接返回内容,否则判断认证中心是否登录过。

         ②如果认证中心已登录告诉业务系统创建session再返回受限内容,否则返回到登录界面。

      1. 如何判断业务系统登录过呢?

        思路:业务系统判断是否存在session

        实现代码及解释:此处session中的SSO_CLIENT_ISLOGINED属性是登录后设置的值,如果没登录就不会有这个属性。

    //判断是否登录
    private boolean isLogined(HttpServletRequest request){
      String SSO_CLIENT_ISLOGINED = (String) request.getSession().getAttribute("SSO_CLIENT_ISLOGINED");
      if("true".equals(SSO_CLIENT_ISLOGINED)) return true;
      return false;
    }

      2. 如何判断认证中心登录过呢?

        思路:在业务系统没有登录的情况下,此时业务系统没有任何数据能够验证用户在认证中心登陆过,但是浏览器有登录认证中心的cookie可以证明登录过认证中心;因此让浏览器带着cookie去访问认证中心去判断是否登录比较合适。     

        实现代码及解释:如果未登录重定向至认证中心/validateLogin.do地址,认证中心收到该请求判断是否登录,未登录重定向到登录地址。

        //业务系统的代码
          //4.未登录重定向至向认证中心,认证中心验证是否登录
          else if(!isLogined(req)){
              String validateUrl = ssoHost+VALIDATE_LOGIN_URL+"?requrl="+ java.net.URLEncoder.encode(requestURL, "utf-8")+"&redirecturl="+URLEncoder.encode(loginUrl, "utf-8");
              res.sendRedirect(validateUrl);
              logger.info("SsoFilter:未登录重定向至向认证中心,认证中心验证是否登录,requrl为用户请求的地址用于sso-server重定向(认证中心已登录),redirecturl为系统登录界面地址用于sso-server重定向(认证中心未登录登录)");
              logger.info("SsoFilter:认证地址:"+validateUrl);
          }

      3. 如果认证中心已登录,认证中心怎么告诉业务系统呢? 

        思路:认证中心给业务系统一个"取件码",5分钟之内赶紧到认证中心去取走你的"快递"(这里的快递指的是用户信息

        实现代码及解释:认证中心重定向至业务系统并携带"取件码",业务系统的过滤器发现有"取件码"便会向认证中心请求"快递"

    /**
           * 认证中心发送取件码
           * @Date 2021/04/27 16:26
           * @Comment 验证是否登录
           * browser client->sso server
           * 已登录:重定向至业务系统并附带token
           * 未登录:跳转至业务系统登录界面
          */
          @RequestMapping("/validateLogin")
          public void validateLogin(HttpSession session, HttpServletResponse response,String requrl,String redirecturl) throws IOException {
              User userSessionBean = null;
              if(session!=null){
                  userSessionBean = (User) session.getAttribute("userSessionBean");
              }
              if(userSessionBean!=null){
                  String token = UUID.randomUUID().toString();
                  jedisUtil.set("sso-server:validateToken:"+token,userSessionBean.getUserid(),60);
                  jedisUtil.set("sso-server:validateTokenSessionId:"+token,session.getId(),60);
                  Map para = new HashMap();para.put("ssotoken",token);
                  RedirectUtils.sendRedirect(response,requrl,para);
              }else{
                  Map para = new HashMap();para.put("requrl",requrl);
                  RedirectUtils.sendRedirect(response,redirecturl,para);
              }
              return;
          }
    查看认证中心发送"取件码"
    //3.有待验证token
          else if(hasSsoToken(req)){
              //有sso-server重定向过来的token 进行验证,验证通过执行登录
              logger.info("SsoFilter:有sso-server重定向过来的token,进行验证,验证通过执行登录");
              boolean isValid = this.checkToken(req,res);
              if(isValid){
                  logger.info("SsoFilter:sso-server验证通过");
                  filterChain.doFilter(servletRequest, servletResponse);
              }else{
                  logger.info("SsoFilter:sso-server未验证通过,跳转至登录界面");
                  res.sendRedirect(loginUrl);
              }
          }
    private boolean hasSsoToken(HttpServletRequest request){
                String ssotoken = request.getParameter("ssotoken");
                if(ssotoken!=null&&!"".equals(ssotoken)) return true;
                return false;
            }
    查看业务系统收"取件码"
    //校验token
            private boolean checkToken(HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException {
                String ssotoken = request.getParameter("ssotoken");
                Map para = new HashMap<>();
                para.put("ssotoken",ssotoken);
                String res = HttpUtils.sendPost(ssoHost+SsoConstants.VALIDATE_TOKEN_URL+"?ssotoken="+ssotoken+"&remoteurl="+ java.net.URLEncoder.encode(request.getRequestURL().toString(),"UTF-8")+"&timestamp="+System.currentTimeMillis(),new HashMap());
                if(res!=null&&!"".equals(res)){
                    JSONObject json = JSONObject.parseObject(res);
                    String status = (String) json.get("status");
                    String userid = (String) json.get("userid");
                    if("success".equals(status)&&userid!=null&&!"".equals(userid)){//认证中心返回token有效,业务系统执行创建session
                        try {
                            String sessionid = loginRunService.execute(request,response,userid);
                            if(sessionid!=null&&!"".equals(sessionid)){
                                tokenSessionidMap.put(ssotoken,sessionid);//用户退出登录使用
                                sessionidTokenMap.put(sessionid,ssotoken);//用户退出登录使用
                                request.getSession(true).setAttribute("SSO_CLIENT_ISLOGINED","true");
                                return true;
                            }
                        } catch (ServletException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
    
                    }
                }
                return false;
    
            }
    查看业务系统向认证中心取"快递"

    二、单点退出思路

      思路:认证中心退出登录时所有的业务系统都要退出登录,因此在认证中心的session过期和删除时向"已单点登录成功过的系统"发送退出登录请求较为合适

      注意实际业务中退出登录有以下几种情况

        ①业务系统退出登录时向认证中心发送退出登录请求;

        ②用户请求认证中心主动退出登录

        ③认证中心session过期时

      1.如何监听session过期删除操作?

        参考:解决session共享后,session监听销毁事件失效

    三、实现单点登录和单点退出的完整流程图



  • 相关阅读:
    Spring MVC(1)Spring MVC的初始化和流程以及SSM的实现
    Spring(四)Spring与数据库编程
    MyBatis(4)-- 动态SQL
    MyBatis(3)-- Mapper映射器
    MyBatis(2)-- MyBatis配置mybatis-config.xml
    MyBatis(1)-- MyBatis介绍
    计算机网络(2)-- URL、HTTP、HTTPS、HTML
    计算机网络(1)- TCP
    Shell脚本编程
    和为定值的多个数
  • 原文地址:https://www.cnblogs.com/tonghaolang/p/15194371.html
Copyright © 2011-2022 走看看