大家好,我是雄雄,欢迎关注微信公众号:雄雄的小课堂
前言
现在是:2022年4月19日19:56:56
昨天写了个bladex
的单点登录,回想起来还是比较复杂的,今天又收到了个在若依
里面实现单点登录。具体是这样的:别的系统中访问我们的系统,但是用户已经在那边系统登录过了,跳转到这边无需在来一次登录,直接上本系统中继续后续的操作。
实现思路
- 三方系统(也就是需要跳转我们系统的系统),直接请求我们系统的登录页面,挂着
token
参数。 - 在我们系统登录界面,判断请求链接中有没有
token
,没有则正常走登录流程。 - 如果没有
token
,则重新写一个单点登录的接口,去请求。 - 在后台将拿到的
token
,去三方系统中鉴权,通过则继续登录,没有通过则直接返回到登录页面。
实现代码
前端
1.在login
的vue
页面中的created
方法中,调用单点登录的方法。
created() {//平台单独的登录 2022年4月19日11:23:58this.getLoginByNameAndTokenJ();},
2.在methods
中写函数的实现:
/*** 三方平台单点登陆系统 2022年4月19日11:22:33* 只传递token*/getLoginByNameAndTokenJ(){//获取地址栏中的tokenvar 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.tokenconst 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);//密码统一都是123456sysUser.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.loadUserByUsernameauthentication = 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());// 生成tokenreturn tokenService.createToken(loginUser);}
最后就可以了,可能这种方式不是最好的,但是目前仅想到这种方法。
注意事项
- 因为若依的登录方法是带着验证码的,如果不带,则会提示验证码失效
- 目前登录传参的方式是
post
,相对比较安全点。 - 三方系统请求的时候,参数是在链接中挂着,不是很靠谱。