欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

根据AD账号直接单点登录到第三方系统

程序员文章站 2022-06-09 19:02:11
上周在做一个单点登录的任务,今天有时间就整理一下,当时遇到的问题很多,我会慢慢的回忆记录下来。首先这个单点登录我们要构思一下:之前的版本是,跳转的链接url是个固定值,它保存到了数据库,我们点击后输入账号密码登录,它是直接从数据库中获取。而现在我们想要实现的功能是,在A系统通过AD账号登录,直接在A系统内点击B系统图标或文字直接跳转到B系统,无需通过账号密码的其他操作直接进入。同时我们也要保障我们传过去的AD账号一定是安全的(不能明文输出),这时需要我们做个加密和解密的过程。这是我做的一个流程图,仅供...

上周在做一个单点登录的任务,今天有时间就整理一下,当时遇到的问题很多,我会慢慢的回忆记录下来。
首先这个单点登录我们要构思一下:
之前的版本是,跳转的链接url是个固定值,它保存到了数据库,我们点击后输入账号密码登录,它是直接从数据库中获取。而现在我们想要实现的功能是,在A系统通过AD账号登录,直接在A系统内点击B系统图标或文字直接跳转到B系统,无需通过账号密码的其他操作直接进入。同时我们也要保障我们传过去的AD账号一定是安全的(不能明文输出),这时需要我们做个加密和解密的过程。
这是我做的一个流程图,仅供参考:

接下来我们就开始进行代码部分

1、在前端相应跳转位置进行传参。

jumpUrl(item) {
   //B系统单点
    if(item.title == "B系统"){
      const params = new FormData();
      params.append("userAd", sessionStorage.getItem("userAd"));
      this.$post("/getbsystemkey.json", params)
        .then(res => {
          if (res.data){
            if(res.status == "true"){
              window.open(this.$bsystemUrl+"account="+res.data);
            }
          }
        })
        .catch(err => {
          console.log(err);
        });
     }else{
      window.open(item.url);
      this.Linklist(item.linkId);
    }

这里遇到了一个问题:
这是我的问题及解决办法
接口遇到的坑(一)

2、A系统后台进行加密

在加密之前我们需要准备一个密钥key,同时确保A系统和B系统的密钥是同一个,之后才能进行后面的工作。

2.1 在我们的secretkey.porperties加密钥

这里我们就在网上找工具生成密钥,我一直在用的是这个在线密码生成器

bsystemkey=eAcZD5AtD7f5aN5lC5ALz5d3QM5l0ASS

之后在commonVar中引用这个key

public final static String BSYSTEMKEY= propertieKey.getProperty("bsystemkey");
2.2 A系统中进行加密
	/**
	 * 在A系统中进行加密处理
	 */
	@RequestMapping(value = "/getbsystemkey")
	//将你需要的参数传过去
	public ResponseEntity<String> getbsystemkey(Model model, HttpServletRequest request,String userAd) throws Exception{
		//yyyy-MM-dd hh:mm:ss为12时制
		//yyyy-MM-dd HH:mm:ss为24时制
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		// 获取服务器当前时间
		String serversDate = sdf.format(Calendar.getInstance().getTime());
		// 获取配置的密钥
		String bsystemKey=CommonVar.BSYSTEMKEY;
		String bsystemContent = userAd+"&"+serversDate;
		try{
			// 创建ASE工具对象
			SymmetricASEEncoder sae = new SymmetricASEEncoder();
			String token=sae.AESEncode(bsystemKey, bsystemContent);

			/**
			 * 3.return
			 */
			return renderData(true, "Success!", token);
		}catch (Exception e){
			return renderData(false, "Failure!", null);
		}
	}

此时的token中就带有我们的AD和时间,只不过传过去的时候是加密形式的。

2.3 B系统中解密
if("asystem".equals(appId)){
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    boolean flag = false;
    // 获取服务器当前时间
    String serversDate = sdf.format(Calendar.getInstance().getTime());
    // 解密token
    AESUtil sae = new AESUtil();
    //这里的key一定要和上面定义的保持一致
    //将AD和时间进行分割
    String[] str = sae.AESDncode("eAcZD5AtD7f5aN5lC5ALz5d3QM5l0ASS",account).split("&");
    String userAd = str[0];
    String currentTime = str[1];   
    System.out.println("userAd="+userAd+"currentTime"+currentTime);
    //时间对比
     flag=compare(serversDate,currentTime);
     if(flag){
      account=userAd;
     }else{
    	 mv.addObject("msg", "单点key已失效,请重新登录!"); 
     }
   }

解密中也会重新获取一次本地时间,因为我们想要判断在单点跳转过程中,超过你限制的时间(比如1分钟)它会无法跳转,token失效,需要重新点击在跳转。

/**
	 * S时间对比工具
	 * @param time1
	 * @param time2
	 * @return
	 * @throws ParseException
	 */
	public static boolean compare(String time1, String time2) throws ParseException  {
		// 如果想比较日期则写成"yyyy-MM-dd"就可以了
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Calendar nowTime = Calendar.getInstance();//得到当前时间
		// 将字符串形式的时间转化为Date类型的时间
		Date a = sdf.parse(time1);
		Date b = sdf.parse(time2);
		//  设置当前时间
		nowTime.setTime(b);
		//  增加1分钟
		nowTime.add(Calendar.MINUTE, 1);
		b = nowTime.getTime();
		System.out.println(b);
		// Date类的一个方法,如果a早于b返回true,否则返回false
		if (a.before(b))
			return true;
		else
			return false;
	
	}

我的这部分是写到了我之前写好的一个接口里,因为我发现在我新写的接口时,无论怎么加都无法跳转到我写的接口内,而是直接跳转到登录页,(因为我是后接手这个代码具体它的结构和用法还不是很清楚),所以放弃了新写的接口,直接利用之前写好的,你们在写的时候可以自行考虑哈。我的这个仅供参考哈。

3.测试

接下来我们就先校验,我们穿过来的token是否解析成功
因为他是两个项目,所以正常情况下是同时启动2个项目来做测试,但是我的eclipse和电脑有点low,所以只能启动一个哈。
所以我们就在A系统中写一个main方法做测试,然后启动B系统,最后将这个链接放到postman中测试,看是否通过。

3.1 A系统测试main方法,生成加密后的token
public static void main(String[] args) {
	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	// 获取服务器当前时间
	String serversDate = sdf.format(Calendar.getInstance().getTime());
	// 获取配置的密钥
	String bsystemKey=CommonVar.BSYSTEMKEY;
	//此test为AD账号
	String bsystemContent = "test"+"&"+serversDate;
	try{
		// 创建ASE工具对象
		SymmetricASEEncoder sae = new SymmetricASEEncoder();
		String token=sae.AESEncode(bsystemKey, bsystemContent);
		System.out.println(token);
		/**
		 * 3.return
		 */
		return;
	}catch (Exception e){
		return;
	}
}

这里会生成一个token

//样例
LcGQ6tr8r0xLNz7ZjgUxK8Fx8B1Mxt8nylCeT5Q1GIs=

我们用postman测试,将这个token携带过去
如果postman测试通了证明你的加密解密没有问题,如果失败了,你要检查下,解密是否正确,或者解析工具是否解析成功。
我使用的加密和解密是根据这篇文章java使用AES对称加密和解密
中间也遇到了一些其他小问题,只不过时间长了,我忘记了,先把我想到的记录下来。以上仅供参考。如有疑问,不对的地方,或者是有更好的办法可以解决,请各位亲多多留言,我会虚心请教学习的!!!!

本文地址:https://blog.csdn.net/FannyIf123/article/details/107604776

相关标签: 单点登录