官方文档地址:积木报表
注意:这里使用的 jdk21、spring boot版本为3.3.4
1.引入依赖
<!-- 积木报表-->
<dependency>
<groupId>org.jeecgframework.jimureport</groupId>
<artifactId>jimureport-spring-boot3-starter-fastjson2</artifactId>
</dependency>
2.导入数据表结构
sql脚本地址:mysql 数据库表结构
如果需要将 mysql 转 postgressql,可以参考 xxl-job 的集成及 Mysql 转 PostgresSql 第 4、5 节,然后一张一张表对照,主要是修改默认值。
2.处理 Token 传递
@RequiredArgsConstructor
public class JmReportTokenService implements JmReportTokenServiceI {
/**
* 积木 token head 头
*/
private static final String JM_TOKEN_HEADER = "X-Access-Token";
/**
* auth 相关格式
*/
private static final String AUTHORIZATION_FORMAT = SecurityFrameworkUtils.AUTHORIZATION_BEARER + " %s";
private final IOAuth2TokenApi oauth2TokenApi;
private final IPermissionApi permissionApi;
private final SecurityProperties securityProperties;
/**
* 自定义 API 数据集appian自定义 Header,解决 Token 传递。
* 参考 <a href="http://report.jeecg.com/2222224">api数据集token机制详解</a> 文档
*
* @return 新 head
*/
@Override
public HttpHeaders customApiHeader() {
// 读取积木标标系统的 token
HttpServletRequest request = ServletUtils.getRequest();
String token = request.getHeader(JM_TOKEN_HEADER);
// 设置系统的 token
HttpHeaders headers = new HttpHeaders();
headers.add(securityProperties.getTokenHeader(), String.format(AUTHORIZATION_FORMAT, token));
return headers;
}
/**
* 校验 Token 是否有效,即验证通过
*
* @param token JmReport 前端传递的 token
* @return 是否认证通过
*/
@Override
public Boolean verifyToken(String token) {
Long userId = SecurityFrameworkUtils.getLoginUserId();
if (!Objects.isNull(userId)) {
return true;
}
return buildLoginUserByToken(token) != null;
}
/**
* 获得用户编号
* 虽然方法名获得的是 username,实际对应到项目中是用户编号
*
* @param token JmReport 前端传递的 token
* @return 用户编号
*/
@Override
public String getUsername(String token) {
Long userId = SecurityFrameworkUtils.getLoginUserId();
if (ObjectUtil.isNotNull(userId)) {
return String.valueOf(userId);
}
LoginUser user = buildLoginUserByToken(token);
return user == null ? null : String.valueOf(user.getId());
}
/**
* 基于 token 构建登录用户
*
* @param token token
* @return 返回 token 对应的用户信息
*/
private LoginUser buildLoginUserByToken(String token) {
if (StrUtil.isEmpty(token)) {
return null;
}
// TODO 如下的实现不算特别优雅,主要咱是不想搞的太复杂,所以参考对应的 Filter 先实现了
// ① 参考 TokenAuthenticationFilter 的认证逻辑(Security 的上下文清理,交给 Spring Security 完成)
// 目的:实现基于 JmReport 前端传递的 token,实现认证
TenantContextHolder.setIgnore(true); // 忽略租户,保证可查询到 token 信息
LoginUser user = null;
try {
OAuth2AccessTokenCheckRespDTO accessToken = oauth2TokenApi.checkAccessToken(token);
if (accessToken == null) {
return null;
}
user = new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType())
.setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes());
} catch (ServiceException ignored) {
// do nothing:如果报错,说明认证失败,则返回 false 即可
}
if (user == null) {
return null;
}
SecurityFrameworkUtils.setLoginUser(user, WebUtils.getRequest());
// ② 参考 TenantContextWebFilter 实现(Tenant 的上下文清理,交给 TenantContextWebFilter 完成)
// 目的:基于 LoginUser 获得到的租户编号,设置到 Tenant 上下文,避免查询数据库时的报错
TenantContextHolder.setIgnore(false);
TenantContextHolder.setTenantId(user.getTenantId());
return user;
}
@Override
public String[] getRoles(String token) {
// 设置租户上下文。原因是:/jmreport/** 纯前端地址,不会走 buildLoginUserByToken 逻辑
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
if (loginUser == null) {
return null;
}
TenantContextHolder.setTenantId(loginUser.getTenantId());
// 参见文档 https://help.jeecg.com/jimureport/prodSafe.html 文档
// 适配:如果是本系统的管理员,则转换成 jimu 报表的管理员
Long userId = SecurityFrameworkUtils.getLoginUserId();
return permissionApi.hasAnyRoles(userId, RoleCodeEnum.SUPER_ADMIN.getCode())
? new String[]{"admin"} : null;
}
@Override
public String getTenantId() {
// 补充说明:不能直接通过 TenantContext 获取,因为 jimu 报表前端请求时,没有带上 tenant-id Header
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
if (loginUser == null) {
return null;
}
return StrUtil.toStringOrNull(loginUser.getTenantId());
}
}
@Configuration(proxyBeanMethods = false)
@ComponentScan(basePackages = "org.jeecg.modules.jmreport") // 扫描积木报表的包
public class JmReportConfiguration {
@Bean
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
public JmReportTokenServiceI jmReportTokenService(IOAuth2TokenApi oAuth2TokenApi,
IPermissionApi permissionApi,
SecurityProperties securityProperties) {
return new JmReportTokenService(oAuth2TokenApi, permissionApi, securityProperties);
}
}
文章评论