提交 | 用户 | 时间
|
e7c126
|
1 |
package com.iailab.module.report.framework.jmreport.core.service; |
H |
2 |
|
|
3 |
import cn.hutool.core.util.ObjectUtil; |
|
4 |
import cn.hutool.core.util.StrUtil; |
|
5 |
import com.iailab.framework.common.exception.ServiceException; |
|
6 |
import com.iailab.framework.common.util.servlet.ServletUtils; |
|
7 |
import com.iailab.framework.security.config.SecurityProperties; |
|
8 |
import com.iailab.framework.security.core.LoginUser; |
|
9 |
import com.iailab.framework.security.core.util.SecurityFrameworkUtils; |
|
10 |
import com.iailab.framework.tenant.core.context.TenantContextHolder; |
|
11 |
import com.iailab.framework.web.core.util.WebFrameworkUtils; |
|
12 |
import com.iailab.module.system.api.oauth2.OAuth2TokenApi; |
|
13 |
import com.iailab.module.system.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO; |
|
14 |
import com.iailab.module.system.api.permission.PermissionApi; |
|
15 |
import com.iailab.module.system.enums.permission.RoleCodeEnum; |
|
16 |
import lombok.RequiredArgsConstructor; |
|
17 |
import org.jeecg.modules.jmreport.api.JmReportTokenServiceI; |
|
18 |
import org.springframework.http.HttpHeaders; |
|
19 |
|
|
20 |
import javax.servlet.http.HttpServletRequest; |
|
21 |
import java.util.Objects; |
|
22 |
|
|
23 |
/** |
|
24 |
* {@link JmReportTokenServiceI} 实现类,提供积木报表的 Token 校验、用户信息的查询等功能 |
|
25 |
* |
|
26 |
* @author 随心 |
|
27 |
*/ |
|
28 |
@RequiredArgsConstructor |
|
29 |
public class JmReportTokenServiceImpl implements JmReportTokenServiceI { |
|
30 |
|
|
31 |
/** |
|
32 |
* 积木 token head 头 |
|
33 |
*/ |
|
34 |
private static final String JM_TOKEN_HEADER = "X-Access-Token"; |
|
35 |
/** |
|
36 |
* auth 相关格式 |
|
37 |
*/ |
|
38 |
private static final String AUTHORIZATION_FORMAT = SecurityFrameworkUtils.AUTHORIZATION_BEARER + " %s"; |
|
39 |
|
|
40 |
private final OAuth2TokenApi oauth2TokenApi; |
|
41 |
private final PermissionApi permissionApi; |
|
42 |
|
|
43 |
private final SecurityProperties securityProperties; |
|
44 |
|
|
45 |
/** |
|
46 |
* 自定义 API 数据集appian自定义 Header,解决 Token 传递。 |
|
47 |
* 参考 <a href="http://report.jeecg.com/2222224">api数据集token机制详解</a> 文档 |
|
48 |
* |
|
49 |
* @return 新 head |
|
50 |
*/ |
|
51 |
@Override |
|
52 |
public HttpHeaders customApiHeader() { |
|
53 |
// 读取积木标标系统的 token |
|
54 |
HttpServletRequest request = ServletUtils.getRequest(); |
|
55 |
String token = request.getHeader(JM_TOKEN_HEADER); |
|
56 |
|
|
57 |
// 设置到 iailab 系统的 token |
|
58 |
HttpHeaders headers = new HttpHeaders(); |
|
59 |
headers.add(securityProperties.getTokenHeader(), String.format(AUTHORIZATION_FORMAT, token)); |
|
60 |
return headers; |
|
61 |
} |
|
62 |
|
|
63 |
/** |
|
64 |
* 校验 Token 是否有效,即验证通过 |
|
65 |
* |
|
66 |
* @param token JmReport 前端传递的 token |
|
67 |
* @return 是否认证通过 |
|
68 |
*/ |
|
69 |
@Override |
|
70 |
public Boolean verifyToken(String token) { |
|
71 |
Long userId = SecurityFrameworkUtils.getLoginUserId(); |
|
72 |
if (!Objects.isNull(userId)) { |
|
73 |
return true; |
|
74 |
} |
|
75 |
return buildLoginUserByToken(token) != null; |
|
76 |
} |
|
77 |
|
|
78 |
/** |
|
79 |
* 获得用户编号 |
|
80 |
* <p> |
|
81 |
* 虽然方法名获得的是 username,实际对应到项目中是用户编号 |
|
82 |
* |
|
83 |
* @param token JmReport 前端传递的 token |
|
84 |
* @return 用户编号 |
|
85 |
*/ |
|
86 |
@Override |
|
87 |
public String getUsername(String token) { |
|
88 |
Long userId = SecurityFrameworkUtils.getLoginUserId(); |
|
89 |
if (ObjectUtil.isNotNull(userId)) { |
|
90 |
return String.valueOf(userId); |
|
91 |
} |
|
92 |
LoginUser user = buildLoginUserByToken(token); |
|
93 |
return user == null ? null : String.valueOf(user.getId()); |
|
94 |
} |
|
95 |
|
|
96 |
/** |
|
97 |
* 基于 token 构建登录用户 |
|
98 |
* |
|
99 |
* @param token token |
|
100 |
* @return 返回 token 对应的用户信息 |
|
101 |
*/ |
|
102 |
private LoginUser buildLoginUserByToken(String token) { |
|
103 |
if (StrUtil.isEmpty(token)) { |
|
104 |
return null; |
|
105 |
} |
|
106 |
// TODO 如下的实现不算特别优雅,主要咱是不想搞的太复杂,所以参考对应的 Filter 先实现了 |
|
107 |
|
|
108 |
// ① 参考 TokenAuthenticationFilter 的认证逻辑(Security 的上下文清理,交给 Spring Security 完成) |
|
109 |
// 目的:实现基于 JmReport 前端传递的 token,实现认证 |
|
110 |
TenantContextHolder.setIgnore(true); // 忽略租户,保证可查询到 token 信息 |
|
111 |
LoginUser user = null; |
|
112 |
try { |
|
113 |
OAuth2AccessTokenCheckRespDTO accessToken = oauth2TokenApi.checkAccessToken(token).getCheckedData(); |
|
114 |
if (accessToken == null) { |
|
115 |
return null; |
|
116 |
} |
|
117 |
user = new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType()) |
|
118 |
.setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes()); |
|
119 |
} catch (ServiceException ignored) { |
|
120 |
// do nothing:如果报错,说明认证失败,则返回 false 即可 |
|
121 |
} |
|
122 |
if (user == null) { |
|
123 |
return null; |
|
124 |
} |
|
125 |
SecurityFrameworkUtils.setLoginUser(user, WebFrameworkUtils.getRequest()); |
|
126 |
|
|
127 |
// ② 参考 TenantContextWebFilter 实现(Tenant 的上下文清理,交给 TenantContextWebFilter 完成) |
|
128 |
// 目的:基于 LoginUser 获得到的租户编号,设置到 Tenant 上下文,避免查询数据库时的报错 |
|
129 |
TenantContextHolder.setIgnore(false); |
|
130 |
TenantContextHolder.setTenantId(user.getTenantId()); |
|
131 |
return user; |
|
132 |
} |
|
133 |
|
|
134 |
@Override |
|
135 |
public String[] getRoles(String token) { |
874287
|
136 |
// 设置租户上下文。原因是:/jmreport/** 纯前端地址,不会走 buildLoginUserByToken 逻辑 |
H |
137 |
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); |
|
138 |
if (loginUser == null) { |
|
139 |
return null; |
|
140 |
} |
|
141 |
TenantContextHolder.setTenantId(loginUser.getTenantId()); |
|
142 |
|
e7c126
|
143 |
// 参见文档 https://help.jeecg.com/jimureport/prodSafe.html 文档 |
H |
144 |
// 适配:如果是本系统的管理员,则转换成 jimu 报表的管理员 |
|
145 |
Long userId = SecurityFrameworkUtils.getLoginUserId(); |
|
146 |
return permissionApi.hasAnyRoles(userId, RoleCodeEnum.SUPER_ADMIN.getCode()).getCheckedData() |
|
147 |
? new String[]{"admin"} : null; |
|
148 |
} |
|
149 |
|
|
150 |
@Override |
|
151 |
public String getTenantId() { |
|
152 |
// 补充说明:不能直接通过 TenantContext 获取,因为 jimu 报表前端请求时,没有带上 tenant-id Header |
|
153 |
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); |
|
154 |
if (loginUser == null) { |
|
155 |
return null; |
|
156 |
} |
|
157 |
return StrUtil.toStringOrNull(loginUser.getTenantId()); |
|
158 |
} |
|
159 |
|
|
160 |
} |