实现第三方系统单点登录

思路举例:

  以QQ为例:pc端QQ界面中所有的第三方软件系统,以QQ邮箱举例,

  QQ中成功登陆,从而点击QQ邮箱可以直接打开网页进入邮箱并无需登录

  在这里就使用了单点登录,QQ邮箱就是QQ信任的第三方系统,双方达成协议,

  双方需要把加密方式,和加密串达成一致。当然如果公司是中型企业,加密串后期

  会有运维去和客户沟通。 接下来贴代码。

代码实例:

  首先设置一个加密串,这里是在properties文件中定义,嫌麻烦可以直接在接口中定义静态私有属性

  #秘钥
  AtsecretKey=Activity0CoJUm6123456789
  

  
 //引入秘钥 
@Value("${AtsecretKey}") private String AtsecretKey; /** * 根据请求的参数加密判断 * @param currTime * @param idcardno * @param type * @param signature * @return */ @RequestMapping("/token") @ResponseBody public ResultEntity checkToken(String currTime,String idcardno,String type,String signature ){ ResultEntity resultEntity=new ResultEntity(); Map<String,String> desMap=new HashMap<>(); desMap.put("currTime",currTime); desMap.put("idcardno",idcardno); desMap.put("type",type); StringBuffer sb = new StringBuffer(); StringBuffer sbkey = new StringBuffer(); Set es = desMap.entrySet(); //所有参与传参的参数按照accsii排序(升序) Iterator it = es.iterator(); while(it.hasNext()) { Map.Entry entry = (Map.Entry)it.next(); String k = (String)entry.getKey(); Object v = entry.getValue(); //空值不传递,不参与签名组串 if(null != v && !"".equals(v)) { sb.append(v); sbkey.append(v); } } sbkey=sbkey.append(AtsecretKey); System.out.println("字符串:"+sbkey.toString()); String md5Item = MD5Util.md5(sbkey.toString()); System.out.println("MD5加密值:"+md5Item); System.out.println(sb.toString()+"sign="+md5Item); //拼字符串后加密 if (md5Item.equals(signature)){ long nowTime=System.currentTimeMillis(); if (((nowTime - Long.parseLong(currTime))*1.0 /(1000 * 60))>20){ resultEntity.setState(HttpCode.FAILED); resultEntity.setRetMessage("认证时间超时"); return resultEntity; } DESPlus desPlus=new DESPlus(); String strJson=JsonUtils.toJson(desMap); String desMessage=desPlus.encrypt(strJson); resultEntity.setState(HttpCode.SUCCESS); resultEntity.setMessage("认证通过"); resultEntity.setResult(desMessage); return resultEntity; } resultEntity.setState(HttpCode.FAILED); resultEntity.setMessage("请求失败"); return resultEntity; }
代码解释:
  ResultEntity:工具类,用于封装json数据,返回页面响应请求
  currTime:时间戳
  idcardno:身份证号
  type:设备类型手机或者pc  
   signature:加密串,

  
Map<String,String> desMap=new HashMap<>();
        desMap.put("currTime",currTime);
        desMap.put("idcardno",idcardno);
        desMap.put("type",type);

将参数放入map中,方便接下来排序

StringBuffer sb = new StringBuffer();
        StringBuffer sbkey = new StringBuffer();
        Set es = desMap.entrySet();  //所有参与传参的参数按照accsii排序(升序)
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            Object v = entry.getValue();
            //空值不传递,不参与签名组串
            if(null != v && !"".equals(v)) {
                sb.append(v);
                sbkey.append(v);
            }
sbkey=sbkey.append(AtsecretKey);
System.out.println("字符串:"+sbkey.toString());
String md5Item = MD5Util.md5(sbkey.toString());
System.out.println("MD5加密值:"+md5Item);
System.out.println(sb.toString()+"sign="+md5Item);
 
 
这里需要用的accsii排序,accsii详细解释可以去查一下
通过迭代器迭代排序,并且清除空值,然后将值封装好key,value
另外在排序后的值后面加上加密串(
AtsecretKey),生成加密签名
接着使用md5工具类加密参数
//拼字符串后加密
        if (md5Item.equals(signature)){
            long nowTime=System.currentTimeMillis();
            if (((nowTime - Long.parseLong(currTime))*1.0 /(1000 * 60))>20){
                resultEntity.setState(HttpCode.FAILED);
                resultEntity.setRetMessage("认证时间超时");
                return resultEntity;
            }
            DESPlus desPlus=new DESPlus();
            String strJson=JsonUtils.toJson(desMap);
            String desMessage=desPlus.encrypt(strJson);
            resultEntity.setState(HttpCode.SUCCESS);
            resultEntity.setMessage("认证通过");
            resultEntity.setResult(desMessage);
            return resultEntity;
        }
        resultEntity.setState(HttpCode.FAILED);
        resultEntity.setMessage("请求失败");
        return resultEntity;
这里将加密后得参数和第三方传的signature判断是否相同,如果相同证明是信任的第三方,
才可以执行下面的操作
拿到第三方发送的时间戳(currTime)并且获取当前的时间戳,设置时间戳过期时间,
这里是防止恶意攻击,不可能第二天还可以拿着前一天的请求来访问,
成功设置后在使用DES加密,因为des是可以解密的,将之前map的参数在一次用des加密,
转换成json数据,让后放进工具类返回请求,第三方拿到参数,再次带着参数来访问接口,

/**
     * 根据第三方的Token来处理单点登录
     * @param request
     * @param session
     * @return
     */
    @RequestMapping("/IntoLogin")
    public String intoLogin( HttpServletRequest request, HttpSession session,String token){
        //拿到token解密
        DESPlus desPlus=new DESPlus();
        try {
            String decToken=desPlus.decrypt(token);
            Map<String,String>map=JsonUtils.fromJson(decToken,Map.class);
            ReaderEntity record = new ReaderEntity();
            record.setCardno(map.get("cardno"));
            record.setIdcardno(map.get("idcardno"));
            String type=map.get("type");
            String currTime=map.get("currTime");
            ReaderSession readerSession =null;
            long nowTime=System.currentTimeMillis();
            //判断过期时长,请求时间超过20分钟就无效
            if (((nowTime - Long.parseLong(currTime))*1.0 /(1000 * 60))<20) {
                readerSession = readerService.login(record, request);
            }
            if(readerSession!=null) {
                    session.setAttribute("readerInfo", readerSession);
                    UnionUserSession unionUserSession = new UnionUserSession();
                    unionUserSession.setUserType(2);
                    unionUserSession.setUserId(readerSession.getReader().getRecno().toString());
                    request.getSession().setAttribute(UnionUserSession.SESSION_ID, unionUserSession);
                    //这里判断密钥类型是pc还是移动端,登录后将跳转不同页面
                    if (type.equals("0")){
                        return "/pc/index";
                    }else{
                        return "/mobile/activity/home";
                        }
                    }
        }catch (Exception e) {
            return "/pc/index";
        }
        return "/pc/index";
    }

这里的代码不多做解释,应该能看得懂,其实这种单点登录思路要屡清楚

为了安全性参数一定是要加密的,特别是加密协议,密钥是双方知道的,第三方

请求的时候也是带着参数可已经加密的参数来求接口,如果我们拿着他们的参数排序

在加上密钥以后加密,发现加密后的字符串一致说明是我们信任的第三方,

这里单点登录要用两个接口,所以我们需要使用des加密后返回给他们再次请求,

一个接口负责判断是否第三方,另一个接口登录,

这里只提供接口供第三方访问。



 

猜你喜欢

转载自www.cnblogs.com/yyKong/p/10855551.html