若依实现单点登录(解析请求链接中的参数做鉴权认证)

2年前 (2022) 程序员胖胖胖虎阿
330 0 0

若依实现单点登录(解析请求链接中的参数做鉴权认证)

大家好,我是雄雄,欢迎关注微信公众号:雄雄的小课堂

前言

现在是:2022年4月19日19:56:56

昨天写了个bladex的单点登录,回想起来还是比较复杂的,今天又收到了个在若依里面实现单点登录。具体是这样的:别的系统中访问我们的系统,但是用户已经在那边系统登录过了,跳转到这边无需在来一次登录,直接上本系统中继续后续的操作。

实现思路

  1. 三方系统(也就是需要跳转我们系统的系统),直接请求我们系统的登录页面,挂着token参数。
  2. 在我们系统登录界面,判断请求链接中有没有token,没有则正常走登录流程。
  3. 如果没有token,则重新写一个单点登录的接口,去请求。
  4. 在后台将拿到的token,去三方系统中鉴权,通过则继续登录,没有通过则直接返回到登录页面。

实现代码

前端

1.在loginvue页面中的created方法中,调用单点登录的方法。

	created() {

	    //平台单独的登录  2022年4月19日11:23:58
	    this.getLoginByNameAndTokenJ();
  },

2.在methods中写函数的实现:

	/**
     * 三方平台单点登陆系统 2022年4月19日11:22:33
     * 只传递token
     */
    getLoginByNameAndTokenJ(){
      //获取地址栏中的token
      var token = this.$route.query.token;

      //调用登录的接口
      if(token==''||token==undefined||token==null){
        //不是那边系统过来的,不走这个地方(阻止created的方法继续向下走)
        
      }else{
      	//转圈圈,不要看到登陆页面,无感体验
        this.loading = true;
        var logininfo= {
          "token":token
        };

        //执行另一套登录操作
        //不是本系统的用户,去J平台登陆去
        this.$store.dispatch("LoginJHaveToken", logininfo).then(() => {
          this.$message.success("登录成功");
          this.loading = false;
          //判断当前角色
          getInfo().then((res) => {
            //获取角色名称
            var rolesName = res.roles[0];
            //获取所属场馆
            this.deptInfo = res.dept;
            sessionStorage.setItem("ssUserName", res.user.nickName);
            //如果是场馆管理员
            if (rolesName === 'changguanmanager') {
              this.$router.push({
                path: "/VenueKanban",
                query: {changguan: res, aa: 0},
                replace: true
              }).catch(() => {
              });
              //否则就是其他用户
            } else {
              this.$router.push({path: this.redirect || "/"}).catch(() => {
              });
            }
          });
        }).catch(err=> {
          console.log("有异常信息",err);
          //异常信息
          this.loading = false;
          if (this.captchaOnOff) {
            this.getCode();
          }
        });
      }
    },

3.在user.js中,实现LoginJHaveToken方法:

	//平台带着token登录,不需要输入账号密码
    //密码都是123456,
    //还需要带着token验证一下
    LoginJHaveToken({ commit }, userInfo) {
      const token = userInfo.token
      const queryParams ={
        'token':token
      };
      return new Promise((resolve, reject) => {
        getLoginByJHaveToken(queryParams).then(res => {
          setToken(res.token)
          commit('SET_TOKEN', res.token)
          resolve()
        }).catch(error => {
          reject(error)
        })
      })
    },

4.在login.js中,实现getLoginByJHaveToken方法:

	/**
	 * 平台带着tonken进行登录
	 *
	 * @param queryParam
	 * @returns {*}
	 */
	export function getLoginByJHaveToken(queryParam) {
	  return request({
	    url: '/ToThirdPart/toThirdPartGetAuthJHaveToken',
	    method: 'post',
	    params: queryParam
	  })
	}


后端

1.在/ToThirdPart/toThirdPartGetAuthJHaveToken控制器中实现登录的操作:


	/**
     * @Description: 平台带着token来系统里面登陆
     * 这边需要做两个步骤:
     * 1.检测数据库里面有没有这个用户名,有则不操作,无则添加
     * 2.去平台验证一下Token是否有,有的话继续操作后面的登录
     * 平台没有这个token,则直接打回去,不让上来
     * @author: 穆雄雄
     * @date: 2022/4/19 上午 11:38
     * @Return: com.ruoyi.common.core.domain.AjaxResult
     */
    @PostMapping("/toThirdPartGetAuthJHaveToken")
    @ApiOperation(value = "平台带着token过来登录")
    public AjaxResult toThirdPartGetAuthJHaveToken(String token) {

        //调用验证token的方法
        JSONObject jsonObject = checkJToken(token);
        String code = jsonObject.getString("code");
        Integer level = 0;
        String loginName = "";
        Long organId = null;
        //返回结果
        AjaxResult ajax = null;
        if (code.equals("0")) {
            //验证成功
            JSONObject dataObject = jsonObject.getJSONObject("data");
            //拿到其他的信息
            level = dataObject.getInteger("level");
            loginName = dataObject.getString("name");
            organId = dataObject.getLong("organId");
        } else {
            ajax = AjaxResult.error(jsonObject.getString("msg"));
            return ajax;
        }

        String isUserNameHas = "";
        //检测一下用户名存在不存在
        if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(loginName))) {
            isUserNameHas = "用户已存在,不需要执行添加的操作";
        } else {
            //用户不存在时,将用户添加到数据库中
            SysUser sysUser = new SysUser();
            //登录名
            sysUser.setUserName(loginName);
            //昵称
            sysUser.setNickName(loginName);
            //密码统一都是123456
            sysUser.setPassword(SecurityUtils.encryptPassword("123456"));
            //创建者,标识J平台过来的用户
            sysUser.setCreateBy("j_have_token");
            //创建日期
            sysUser.setCreateTime(new Date());
            //所属等级
            sysUser.setHierarchy(level);
            //明文
            sysUser.setMingwen("123456");
            //账户权限:为了区分是平台的用户还是本系统用户

            //id返回来之后需要加上
            sysUser.setDeptId(organId);

            //所属等级如果没有,则角色是全国的
            //1  省  2 市     3  区
            if (level == null) {
                //角色
                Long[] roleids = {104L};
                sysUser.setRoleIds(roleids);
            } else {
                Long[] roleids = {100L};
                sysUser.setRoleIds(roleids);
            }
            int rows = userService.insertUser(sysUser);
            if (rows > 0) {
                isUserNameHas = "添加成功";
            }
        }
        ajax = AjaxResult.success();
        // 生成令牌(不加验证码登录)
        String tokenNew = loginService.loginNoCode(loginName, "123456", null);
        ajax.put(Constants.TOKEN, tokenNew);
        ajax.put("isUserNameHas", isUserNameHas);
        ajax.put("msg", "登录成功");
        return ajax;
    }

2.鉴权方法checkJToken,验证token是否存在,存在则返回用户信息,不存在则打回去:

	 /**
     * 检测一下J平台的token 对不对
     *
     * @param token
     * @return
     */
    public JSONObject checkJToken(String token) {
        JSONObject jsonObject = new JSONObject();
        //测试环境
        String baseUrl = "http://xxxxx/checkTokenRtnInfo?stk=" + token;
        HttpResponse d = HttpRequest.get(baseUrl)
                .header(HttpHeaders.CONTENT_TYPE, "application/json")
                .header(HttpHeaders.ACCEPT, "application/json")
                .execute();
        return (JSONObject) JSONObject.parse(d.body().toString());
    }

3.绕过验证码登录的方法,重写loginService.loginNoCode方法:

	
    /**
     * 不加验证码登录
     *
     * @param username 用户名
     * @param password 密码
     * @param uuid 唯一标识
     * @return 结果
     */
    public String loginNoCode(String username, String password,  String uuid)
    {
        // 用户验证
        Authentication authentication = null;
        try
        {
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager
                    .authenticate(new UsernamePasswordAuthenticationToken(username, password));
        }
        catch (Exception e)
        {
            if (e instanceof BadCredentialsException)
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            }
            else
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        recordLoginInfo(loginUser.getUserId());
        // 生成token
        return tokenService.createToken(loginUser);
    }


最后就可以了,可能这种方式不是最好的,但是目前仅想到这种方法。

注意事项

  1. 因为若依的登录方法是带着验证码的,如果不带,则会提示验证码失效
  2. 目前登录传参的方式是post,相对比较安全点。
  3. 三方系统请求的时候,参数是在链接中挂着,不是很靠谱。

相关文章

暂无评论

暂无评论...