时间:2022-05-24

现在使用若依框架进行开发的公司及个人很多,这个一个优秀的开源框架。目前碰到这样一个需求,甲方目前现有一个平台系统,需要在这个平台系统中调用 我们新开发的系统,希望登录平台后,能够不再登录进入新开发的系统,即所谓的单点登录。这个需求不能用我们常见的CAS 做鉴权,从而实现多系统单点登录。

流程图:

实现思路
1、三方系统(也就是需要跳转我们系统的系统),直接请求我们系统的登录页面,挂着token参数。

2、在我们系统登录界面,判断请求链接中有没有token,没有则正常走登录流程。

3、如果没有token,则重新写一个单点登录的接口,去请求。

4、在后台将拿到的token,去三方系统中鉴权,通过则继续登录,没有通过则直接返回到登录页面。

实现代码

前端

1.新建thirdPlatLoginvue页面,调用单点登录的方法。【新建无内容页面,不用现有的login页面,主要是避免第三方平台调用时闪现登录框】

在后台将拿到的token,去三方系统中鉴权,通过则继续登录,没有通过则直接返回到登录页面。

thirdPlatlogin.vue 代码如下:

<template>
 <div> </div>
</template>

<script>
export default {
  name: "Login",
  data() {
    return {

      loginRules: {

      },
      loading: false,
      // 验证码开关
      captchaOnOff: true,
      // 注册开关
      register: false,
      redirect: undefined
    };
  },
  watch: {
  },
  created() {

    //平台单独的登录  2022年4月19日11:23:58
    this.getLoginByNameAndTokenJ();
  },
  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);

                this.$router.push({path: this.redirect || "/"}).catch(() => {
                });

                // //如果是场馆管理员
                // 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();
              // }
            });
          }
        },
  }
};
</script>

<style rel="stylesheet/scss" lang="scss">

</style>

2、在store->modules的user.js中,实现LoginJHaveToken方法:3

    //平台带着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)
            })
          })
        }

 3、在api目录的login.js中,实现getLoginByJHaveToken方法:

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

4、在router的index.js中,添加如下路由:

  {
    path: '/thirdPlatlogin',
    component: () => import('@/views/thirdPlatlogin'),
    hidden: true
  },

5、在src的permission.js中,修改白名单如下:

const whiteList = ['/login', '/auth-redirect', '/bind', '/register','/thirdPlatlogin']

后台:

1.新建第三方平台登录Controller

代码如下:

package com.ruoyi.web.controller.system;

import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.framework.web.service.SysLoginService;
import com.ruoyi.system.service.ISysPostService;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService;

import jodd.http.HttpRequest; //导入方法依赖的package包/类
import io.swagger.annotations.ApiOperation;
import jodd.http.HttpResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

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

    @Autowired
    private ISysRoleService roleService;

    @Autowired
    private ISysPostService postService;
    @Autowired
    private SysLoginService loginService;

    @PostMapping("/toThirdPartGetAuthJHaveToken")
    @ApiOperation(value = "平台带着token过来登录")
    public AjaxResult toThirdPartGetAuthJHaveToken(String token) {

        //调用验证token的方法
        JSONObject jsonObject = checkJToken(token);
//以下测试用
//        JSONObject jsonObject =new JSONObject();
//        jsonObject.put("code","0");
//        JSONObject jsonObjectData =new JSONObject();
//        jsonObjectData.put("name","zhansan");
//        jsonObject.put("data",jsonObjectData);
//        jsonObject.put("msg","验证成功");

        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");
            //拿到其他的信息
            loginName = dataObject.getString("name");
        } 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;
    }

    /**
     * 通过第三方平台接口,鉴定token合法性,并返回userName等登录信息
     * 这个方法需要根据实际需要进行修改
     * @param token
     * @return
     */
    public JSONObject checkJToken(String token) {
        JSONObject jsonObject = new JSONObject();
        //测试环境
        String baseUrl = "http://xxxxx/checkTokenRtnInfo?stk=" + token;//根据实际地址进行修改
        HttpRequest request = HttpRequest.get(baseUrl)
                .header(HttpHeaders.CONTENT_TYPE, "application/json")
                .header(HttpHeaders.ACCEPT, "application/json");

        HttpResponse response = request.send();
        return (JSONObject) JSONObject.parse(response.bodyText());
    }
}

 2、pom.xml添加如下依赖

        <!-- https://mvnrepository.com/artifact/org.jodd/jodd-http -->
        <dependency>
            <groupId>org.jodd</groupId>
            <artifactId>jodd-http</artifactId>
            <version>6.2.1</version>
        </dependency>

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);
    }

通过以上,第三方平台通过访问 http://localhost:81/thirdPlatlogin?token=%2713%27

就可以实现单点登录。

以上主要参考:若依实现系统单点登录(可绕过验证码)_穆雄雄的博客-CSDN博客

基于雄雄老师的文章,补充详细化。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐