一:集成:
ruoyi-framework 引入以下依赖
<dependency>
<groupId>org.jeecgframework.jimureport</groupId>
<artifactId>jimureport-spring-boot-starter</artifactId>
<version>1.4.0-beta</version>
</dependency>
RuoYiApplication添加积木扫描目录
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class },scanBasePackages = {"org.jeecg.modules.jmreport","com.ruoyi"})
SecurityConfig拦截排除
目录在ruoyi-framework
.antMatchers("/jmreport/**").anonymous()
自定义项目前缀
在application.yml
文件中,自定义项目前缀(主要用于菜单集成)。
jeecg :
jmreport:
#自定义项目前缀,必须与前端 process.env.VUE_APP_BASE_API 的值一致
customPrePath: /dev-api
至此集成完成,访问地址为:http://localhost:8848/jmreport/list
二:报表设计器Token校验及菜单集成
后端部分
每次校验时,需要刷新Token有效期,否则有可能出现报表设计一半,结果Token过期了,导致保存不了,重新登录后,可能得重新重头开始设计的情况。
判断当前角色是不是超管,如果是,则无需进行鉴权,直接通过。
每个用户都有Token,但是除了超管之外,其他所有人都需要判断是否有报表设计器菜单的权限,如果没有,则不让通过
在com.ruoyi.framework.web.service.TokenService
中添加两个方法
/**
* 通过Token获取用户身份信息
*
* @return 用户信息
*/
public LoginUser getLoginUser(String token) {
if (StringUtils.isNotEmpty(token)){
if (token.startsWith(Constants.TOKEN_PREFIX)) {
token = token.replace(Constants.TOKEN_PREFIX, "");
}
try{
Claims claims = parseToken(token);
// 解析对应的权限以及用户信息
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
String userKey = getTokenKey(uuid);
LoginUser user = redisCache.getCacheObject(userKey);
return user;
}catch (Exception e){ }
}
return null;
}
/**
* Token对应的Header名称
*
* @return
*/
public String getHeader() {
return header;
}
com\ruoyi\framework\web\service\添加JimuReportTokenService
类,实现接口 JmReportTokenServiceI
。
package com.ruoyi.framework.web.service;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.StringUtils;
import org.jeecg.modules.jmreport.api.JmReportTokenServiceI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* 自定义积木报表鉴权(如果不进行自定义,则所有请求不做权限控制)
*
*/
@Component
public class JimuReportTokenService implements JmReportTokenServiceI {
@Autowired
private TokenService tokenService;
@Override
public String getToken(HttpServletRequest request) {
//先从url参数中取,若没有,再从header中取
String paramToken = request.getParameter("token");
String headerToken = request.getHeader("token");
if (StringUtils.isEmpty(paramToken)) {
paramToken = headerToken;
}
LoginUser loginUser = tokenService.getLoginUser(paramToken);
if (loginUser != null) {
return paramToken;
}
return "";
}
@Override
public String getUsername(String token) {
LoginUser loginUser = tokenService.getLoginUser(token);
return loginUser.getUsername();
}
/**
* 校验设计器权限
* @param token
* @return
*/
@Override
public Boolean verifyToken(String token) {
LoginUser loginUser = tokenService.getLoginUser(token);
if (StringUtils.isNotNull(loginUser)) {
//刷新Token有效期
tokenService.refreshToken(loginUser);
//超管不需要鉴权
if(loginUser.getUser() != null && loginUser.getUser().isAdmin()){
return true;
}else{
//校验菜单权限
Set<String> permissions = loginUser.getPermissions();
if(permissions != null && permissions.contains("report:jimu:list")){
return true;
}
}
}
return false;
}
/**
* 系统上下文变量(http://report.jeecg.com/2159712)
* @param token
* @return
*/
@Override
public Map<String, Object> getUserInfo(String token) {
Map<String, Object> map = new HashMap(5);
LoginUser loginUser = tokenService.getLoginUser(token);
//设置用户名
map.put(SYS_USER_CODE, loginUser.getUsername());
//设置部门编码
map.put(SYS_ORG_CODE, loginUser.getDeptId());
// 将所有信息存放至map 解析sql/api会根据map的键值解析
return map;
}
@Override
public HttpHeaders customApiHeader() {
HttpHeaders header = new HttpHeaders();
//主要用于API数据源。默认给API数据源的header中携带上Token。
//如使用当前项目的API,则需要在header中携带Authorization头
header.add(tokenService.getHeader(), getToken());
header.add("token", getToken());
header.add("X-Access-Token", getToken());
return header;
}
}
报表查看权限校验关键点:
判断当前角色是不是超管,如果是,则无需进行鉴权,直接通过。
判断当前用户是否有设计器的权限,如果有,那也无需进行报表查看权限的校验
除此之外,其他所有人都需要判断是否有对应报表的查看权限,即只允许查看被授权的报表。
每个Jimu报表都有一个报表ID,在菜单权限标识符中,加上该ID,即可做到区分不同报表的权限控制。
com\ruoyi\framework\interceptor\新增拦截规则JmReportInterceptor
,实现HandlerInterceptor
类,重写preHandle
方法
package com.ruoyi.framework.interceptor;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Set;
/**
* 拦截积木报表查看访问路由,校验权限
*
*/
@Component
public class JmReportInterceptor implements HandlerInterceptor {
@Autowired
private TokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getParameter("token");
LoginUser loginUser = tokenService.getLoginUser(token);
if (loginUser != null) {
//超管不需要鉴权
if(loginUser.getUser() != null && loginUser.getUser().isAdmin()){
return true;
}else{
//获取权限集合
Set<String> permissions = loginUser.getPermissions();
//如果拥有设计器的权限,则无需view权限,也可以通过校验
if(permissions != null && permissions.contains("report:jimu:list")){
return true;
}
//其余情况,一般是通过报表菜单点击进来的,校验是否有对应报表的权限:report:jimu:view:{reportId}
//http../jmreport/view/717968580806651904,则reportId = 717968580806651904
String reportId = StringUtils.substringAfterLast(request.getRequestURI(), "/");
String viewPerm = "report:jimu:view:" + reportId;
if(permissions != null && permissions.contains(viewPerm)){
return true;
}
}
}
AjaxResult ajaxResult = AjaxResult.error("参数错误或没有该报表的访问权限!");
ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult));
return false;
}
}
将拦截规则添加到配置中com.ruoyi.framework.config.ResourcesConfig.addInterceptors
@Autowired
private JmReportInterceptor jmReportInterceptor;
/**
* 自定义拦截规则(该方法原来就有)
*/
@Override
public void addInterceptors(InterceptorRegistry registry)
{
registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
//增加下边这句
registry.addInterceptor(jmReportInterceptor).addPathPatterns("/jmreport/view/**");
}
------
前端部分
ruoyi-ui\src\views\report\jimu\design\index.vue
<template>
<i-frame :src="openUrl" id="jimuReportFrame" />
</template>
<script>
import { getToken } from '@/utils/auth'
import iFrame from "@/components/iFrame/index";
export default {
name: 'JimuReportDesign',
components: { iFrame },
data() {
return {
openUrl: process.env.VUE_APP_BASE_API + '/jmreport/list?token=Bearer ' + getToken()
}
},
}
</script>
<style scoped>
</style>
ruoyi-ui\src\views\report\jimu\view\index.vue
<template>
<i-frame :src="openUrl" />
</template>
<script>
import { getToken } from '@/utils/auth'
import iFrame from "@/components/iFrame/index";
export default {
name: 'JimuReportView',
components: { iFrame },
data() {
return {
openUrl: '',
}
},
created() {
const reportId = this.$route.path.substring(this.$route.path.lastIndexOf("/")+1)
this.openUrl = process.env.VUE_APP_BASE_API + '/jmreport/view/' + reportId + '?token=Bearer ' + getToken()
}
}
</script>
<style scoped>
</style>
-----------
菜单部分
报表设计器菜单配置:
路由地址:jimu/design
组件路径:report/jimu/design/index
权限字符:report:jimu:list
具体显示页面菜单配置:
路由地址:jimu/view/810683101242523648
组件地址:report/jimu/view/index
权限字符:report:jimu:view:810683101242523648
810683101242523648为{reportId},reportId就是预览界面URL中的报表ID
至此积木报表集成完毕
--