Browse Source

提交开源任务材料

master
LAPTOP-SB56SG4Q\86185 2 years ago
parent
commit
a7a23edee9
  1. 5
      README.md
  2. BIN
      doc/IAM对接代码参考.rar
  3. 275
      doc/IAM对接代码参考/SysOamOauth.java
  4. 61
      doc/IAM对接代码参考/config-index.js
  5. 271
      doc/IAM对接代码参考/router-index.js
  6. BIN
      doc/JSD-9647-需求确认书V1.docx
  7. BIN
      doc/JSD-9880-需求确认书V1.docx
  8. 62
      doc/jsd9880.postman_collection测试用例.json
  9. BIN
      doc/一汽解放_IAM身份管理项目-业务系统登录认证接入规范-v1.5(1).docx
  10. BIN
      doc/解放IAM单点登录插件使用文档.docx
  11. BIN
      lib/finekit-10.0-20200828.jar
  12. 21
      plugin.xml
  13. 120
      src/main/java/com/fr/plugin/GetTicket.java
  14. 63
      src/main/java/com/fr/plugin/GoAuthApi.java
  15. 52
      src/main/java/com/fr/plugin/HttpUtils.java
  16. 166
      src/main/java/com/fr/plugin/IAMloginFilter.java
  17. 70
      src/main/java/com/fr/plugin/Oauth2Config.java
  18. 122
      src/main/java/com/fr/plugin/TCAuthCallbackApi.java
  19. 25
      src/main/java/com/fr/plugin/TCauth2HandlerProvider.java
  20. 27
      src/main/java/com/fr/plugin/TCauth2URLAliasBridge.java
  21. 11
      src/main/resources/com/fr/plugin/redirect.html

5
README.md

@ -1,3 +1,6 @@
# open-JSD-9647
JSD-9647 IAM OAuth2单点
JSD-9647 IAM OAuth2单点\
免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\
仅作为开发者学习参考使用!禁止用于任何商业用途!\
为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。

BIN
doc/IAM对接代码参考.rar

Binary file not shown.

275
doc/IAM对接代码参考/SysOamOauth.java

@ -0,0 +1,275 @@
package com.fawjiefang.modules.sys.controller;
import cn.hutool.core.codec.Base64;
import com.fawjiefang.common.cmodules.log.entity.SysLogLoginEntity;
import com.fawjiefang.common.cmodules.log.enums.LoginOperationEnum;
import com.fawjiefang.common.cmodules.log.enums.LoginStatusEnum;
import com.fawjiefang.common.cmodules.log.service.SysLogLoginService;
import com.fawjiefang.common.common.redis.RedisUtils;
import com.fawjiefang.common.common.utils.IpUtils;
import com.fawjiefang.common.common.utils.Result;
import com.fawjiefang.common.entity.UserCache;
import com.fawjiefang.common.utils.AesEncryptUtil;
import com.fawjiefang.modules.security.service.SysUserTokenService;
import com.fawjiefang.modules.sys.dto.SysUserDTO;
import com.fawjiefang.modules.sys.service.SysDictService;
import com.fawjiefang.modules.sys.service.SysUserService;
import io.swagger.annotations.ApiOperation;
import org.activiti.engine.impl.util.json.JSONObject;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.Map;
@RestController
@RequestMapping("/idm")
public class SysOamOauth {
@Autowired
private SysUserTokenService sysUserTokenService;
@Autowired
private SysLogLoginService sysLogLoginService;
@Autowired
private RedisUtils redisUtils;
@Autowired
private SysDictService sysDictService;
//private static String AUTHORIZATION_URL = "https://www.fawidmdev.com/ms_oauth/oauth2/endpoints/oauthservice/authorize";
@Value("${jiefang.admin.authorization-url}")
private String AUTHORIZATION_URL;
@Value("${jiefang.admin.access-token-url}")
private String ACCESS_TOKEN_URL;
@Value("${jiefang.admin.user-profile-url}")
private String USER_PROFILE_URL;
@Value("${jiefang.admin.customer-service-url}")
private String CUSTOMER_SERVICE_URL;
@Value("${jiefang.admin.redirect-uri}")
private String REDIRECT_URI;
private static String CLIENT_ID = "qakz5cr8r61gzzqq5sqioga8ulrfi483";
private static String CLIENT_SECRET = "1aspst1979wz4nt296unf51lvbfng0bs";
private static String BASE_64_CREDENTIALS = "Basic " + new String(Base64.encode(CLIENT_ID+":"+ CLIENT_SECRET));
@Value("${jiefang.admin.home-url}")
private String HOME_URL;
private static String RESPONSE_TYPE = "code";
private static String OAUTH_SCOPE = "Customer.Info UserProfile.me";
private static String GRANT_TYPE = "AUTHORIZATION_CODE";
private static CloseableHttpClient httpClient;
static {
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(100);
cm.setDefaultMaxPerRoute(20);
cm.setDefaultMaxPerRoute(50);
httpClient = HttpClients.custom().setConnectionManager(cm).build();
}
@Autowired
private SysUserService sysUserService;
@RequestMapping("validation")
@ApiOperation("idm验证")
public void validation(@RequestParam(value="code",required=false) String code, HttpServletRequest request, HttpServletResponse response) throws Exception {
if(code == null || "".equals(code)){
//response.sendRedirect(AUTHORIZATION_URL+"?client_id=" + CLIENT_ID + "&response_type=" + RESPONSE_TYPE + "&redirect_uri=" + REDIRECT_URI + "&scope=" + OAUTH_SCOPE + "&domain=IdmDomain");
//response.sendRedirect(AUTHORIZATION_URL+"?response_type=code&client_id= xcoiv98y2kd22vusuye3kch &domain=IdmDomain &scope=ResServer.Customer.Info ResServer.UserProfile.me&redirect_uri="+REDIRECT_URI);
//response.sendRedirect("http://10.60.25.66/oauth2/rest/authz?response_type=code&client_id="+CLIENT_ID+"&domain=IdmDomain&state=xcoiv98y2kd22vusuye3kch&scope=IdmResServer.Customer.Info%20IdmResServer.UserProfile.me&redirect_uri="+REDIRECT_URI);
// response.sendRedirect("https://iamuat.fawjiefang.com.cn/oauth2/rest/authz?response_type=code&client_id=qakz5cr8r61gzzqq5sqioga8ulrfi483&domain=IdmDomain&state=xyz&scope=IdmResServer.UserProfile.me openid email phone profile&redirect_uri=http://10.58.52.112:8686/jiefang-admin/idm/validation");
response.sendRedirect(AUTHORIZATION_URL+"?response_type="+RESPONSE_TYPE+"&client_id="+CLIENT_ID+"&domain=IdmDomain&state=xyz&scope=IdmResServer.UserProfile.me openid email phone profile&redirect_uri="+REDIRECT_URI);
}else{
String accessToken = getAccessToken(code);
System.out.println("accessToken:"+accessToken);
String username = getUserInfo(accessToken);
getCustomerInfo(accessToken,username);
SysUserDTO user = sysUserService.getByUsername(username);
SysLogLoginEntity log = new SysLogLoginEntity();
log.setOperation(LoginOperationEnum.LOGIN.value());
log.setCreateDate(new Date());
log.setIp(IpUtils.getIpAddr(request));
log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
log.setIp(IpUtils.getIpAddr(request));
if(user == null){
log.setStatus(LoginStatusEnum.FAIL.value());
log.setCreatorName(username);
sysLogLoginService.save(log);
response.sendRedirect(HOME_URL);
}else{
sysDictService.refRedisDict();
}
Result r = sysUserTokenService.createToken(user.getId());
//用户信息
Map<String,Object> map = (Map<String, Object>) r.getData();
SetUserCacheToRedis(user);
redisUtils.hSet("userinfo",user.getId().toString(),user);
String key = String.valueOf(System.currentTimeMillis());
String aesUserId = AesEncryptUtil.encrypt(new String(map.get("userId").toString().getBytes(),"UTF-8"),"123"+key,"123"+key);
String aesToken = AesEncryptUtil.encrypt(new String(map.get("token").toString().getBytes(),"UTF-8"),"123"+key,"123"+key);
log.setStatus(LoginStatusEnum.SUCCESS.value());
log.setCreator(user.getId());
log.setCreatorName(user.getUsername());
sysLogLoginService.save(log);
response.sendRedirect(HOME_URL+"?userId="+aesUserId+"&token="+aesToken+"&key="+key);
}
}
private void SetUserCacheToRedis(SysUserDTO user) {
try {
UserCache userCache = new UserCache();
userCache.setEmail(user.getEmail());
userCache.setId(user.getId());
userCache.setMobile(user.getMobile());
userCache.setUsername(user.getUsername());
userCache.setSuperAdmin(user.getSuperAdmin());
redisUtils.hSet("userCache",user.getId().toString(),userCache);
} catch (Exception e) {
}
}
public void getCustomerInfo(String token ,String uid){
if(token != null && uid != null){
for(int i=0;i<100;i++){
System.out.println("token:"+token);
System.out.println("uid:"+uid);
}
}else{
if(token == null){
System.out.println("token空了");
}else{
System.out.println("uid空了");
}
}
}
public String getAccessToken(String code){
String accessToken = null;
String params = "redirect_uri=" + REDIRECT_URI + "&grant_type=" + GRANT_TYPE + "&code=" + code;
System.out.println("参数:"+params);
byte[] postData = params.getBytes(Charset.forName("UTF-8"));
HttpURLConnection connection = null;
OutputStream wr = null;
try {
URL url = new URL(ACCESS_TOKEN_URL);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Authorization",BASE_64_CREDENTIALS);
connection.setRequestProperty("cache-control","no-cache");
connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");
connection.setRequestProperty("X-OAUTH-IDENTITY-DOMAIN-NAME","IdmDomain ");
connection.setDoOutput(true);
wr = new DataOutputStream(connection.getOutputStream());
wr.write(postData);
wr.flush();
wr.close();
BufferedReader rd = new BufferedReader(new InputStreamReader(connection.getInputStream(),Charset.forName("UTF-8")));
String line;
StringBuffer resp = new StringBuffer();
while((line = rd.readLine()) != null){
resp.append(line);
}
rd.close();
JSONObject obj;
obj = new JSONObject(resp.toString());
accessToken = obj.getString("access_token");
}catch (Exception e){
e.printStackTrace();
throw new RuntimeException();
}finally {
if(connection != null){
connection.disconnect();
}
try {
if(wr != null){
wr.flush();
wr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return accessToken;
}
public String getUserInfo(String accessToken){
String uid = null;
CloseableHttpResponse response = null;
BufferedReader in = null;
String result = "";
String params = "Authorization=" + accessToken;
byte[] postData = params.getBytes(Charset.forName("UTF-8"));
HttpURLConnection connection = null;
try {
HttpGet httpGet = new HttpGet(USER_PROFILE_URL);
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30000).setConnectionRequestTimeout(30000).setSocketTimeout(30000).build();
httpGet.setConfig(requestConfig);
httpGet.addHeader("X-OAUTH-IDENTITY-DOMAIN-NAME", "IdmDomain");
httpGet.setHeader("Authorization", "Bearer "+accessToken);
response = httpClient.execute(httpGet);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line;
StringBuffer resp = new StringBuffer();
while((line = rd.readLine()) != null){
resp.append(line);
}
rd.close();
JSONObject obj;
obj = new JSONObject(resp.toString());
uid = obj.getString("sub");
}catch (Exception e){
e.printStackTrace();
throw new RuntimeException();
}finally {
if(connection != null){
connection.disconnect();
}
}
return uid;
}
}

61
doc/IAM对接代码参考/config-index.js

@ -0,0 +1,61 @@
//根据环境,将apiURL赋不同的值
let IDM_APPROVE_URL = ''
let IDM_LOGOUT_URL = ''
let IAM_LOGIN = ''
let UPDATE_PASSWORD_URL = ''
let ENV_NOTICE = ''
switch (process.env.VUE_APP_NODE_ENV) {
case 'dev': //<!-- 开发环境 -->
window.SITE_CONFIG['apiURL'] = 'http://localhost:8686/'
ENV_NOTICE = '开发环境'
break;
case 'sit': //<!-- 集成测试环境 -->
case 'uat': //<!-- 验收测试环境 -- http://10.43.4.132/jiefang-apigateway/ http://10.43.4.132:30686>
window.SITE_CONFIG['apiURL'] = 'http://10.60.215.18:8686/';
IDM_APPROVE_URL = "https://iamuat.fawjiefang.com.cn/oauth2/rest/authz?response_type=code&client_id=qakz5cr8r61gzzqq5sqioga8ulrfi483&domain=IdmDomain&state=xyz&scope=IdmResServer.UserProfile.me%20openid%20email%20phone%20profile&redirect_uri=http://10.60.215.18:8686/jiefang-admin/idm/validation";
IDM_LOGOUT_URL = "https://iamuat.fawjiefang.com.cn/oam/server/logout?end_url=https://iamuat.fawjiefang.com.cn/oauth2/rest/authz%3Fresponse_type=code%26client_id=qakz5cr8r61gzzqq5sqioga8ulrfi483%26domain=IdmDomain%26state=xyz%26scope=IdmResServer.UserProfile.me%2bopenid%2bemail%2bphone%2bprofile%26redirect_uri=http://10.60.215.18:8686/jiefang-admin/idm/validation";
IAM_LOGIN = "https://iamuat.fawjiefang.com.cn/FawIdmCommonUtils/ssoLoginService/goLogout?client_id=qakz5cr8r61gzzqq5sqioga8ulrfi483";
UPDATE_PASSWORD_URL = "https://iamuat.fawjiefang.com.cn/IAMEmployeeExtApp/#/home/user_update_password"
ENV_NOTICE = '测试环境'
break;
case 'prod': //<!-- 生产环境 -->
window.SITE_CONFIG['apiURL'] = 'http://10.60.205.40:8686/';
IDM_APPROVE_URL = "https://iam.fawjiefang.com.cn/oauth2/rest/authz?response_type=code&client_id=qakz5cr8r61gzzqq5sqioga8ulrfi483&domain=IdmDomain&state=xyz&scope=IdmResServer.UserProfile.me%20openid%20email%20phone%20profile&redirect_uri=http://10.60.205.40:8686/jiefang-admin/idm/validation";
IDM_LOGOUT_URL = "https://iam.fawjiefang.com.cn/oam/server/logout?end_url=https://iam.fawjiefang.com.cn/oauth2/rest/authz%3Fresponse_type=code%26client_id=qakz5cr8r61gzzqq5sqioga8ulrfi483%26domain=IdmDomain%26state=xyz%26scope=IdmResServer.UserProfile.me%2bopenid%2bemail%2bphone%2bprofile%26redirect_uri=http://10.60.205.40:8686/jiefang-admin/idm/validation";
IAM_LOGIN = "https://iam.fawjiefang.com.cn/FawIdmCommonUtils/ssoLoginService/goLogout?client_id=qakz5cr8r61gzzqq5sqioga8ulrfi483";
UPDATE_PASSWORD_URL = "https://iam.fawjiefang.com.cn/IAMEmployeeExtApp/#/home/user_update_password"
ENV_NOTICE = '生产环境'
break;
default:
window.SITE_CONFIG['apiURL'] = 'http://localhost:8686/';
break;
}
const DOWNLOAD_URL = "http://localhost:8686/"
const JMPS_BAS_URL = "jiefang-bas"
const JMPS_ADMIN_URL = "jiefang-admin"
const JMPS_FILE_URL = "jiefang-file"
const JMPS_QTMS_URL = "jiefang-qtms"
const PARTS_SUPPLIER = "http://10.60.22.13:8180/tqm-admin/publicsup/publicsup/findbypartgetsup"
const serviceUrl = window.SITE_CONFIG['apiURL'] + "/"
const serviceUrl1 = window.SITE_CONFIG['apiURL']
const partsSupplierUrl = "http://10.60.22.13:8180/tqm-admin/publicsup/publicsup/findbypartgetsup?"
// const IDM_APPROVE_URL = "https://iam.fawjiefang.com.cn/oauth2/rest/authz?response_type=code&client_id=qakz5cr8r61gzzqq5sqioga8ulrfi483&domain=IdmDomain&state=xyz&scope=IdmResServer.UserProfile.me%20openid%20email%20phone%20profile&redirect_uri=http://10.60.205.40:8686/jiefang-admin/idm/validation";
// const IDM_LOGOUT_URL = "https://iam.fawjiefang.com.cn/oam/server/logout?end_url=https://iamuat.fawjiefang.com.cn/oauth2/rest/authz%3Fresponse_type=code%26client_id=qakz5cr8r61gzzqq5sqioga8ulrfi483%26domain=IdmDomain%26state=xyz%26scope=IdmResServer.UserProfile.me%2bopenid%2bemail%2bphone%2bprofile%26redirect_uri=http://10.60.205.40:8686/jiefang-admin/idm/validation";
// const IAM_LOGIN = "https://iam.fawjiefang.com.cn/FawIdmCommonUtils/ssoLoginService/goLogout?client_id=qakz5cr8r61gzzqq5sqioga8ulrfi483";
export default {
JMPS_BAS_URL,
JMPS_ADMIN_URL,
JMPS_QTMS_URL,
serviceUrl,
serviceUrl1,
JMPS_FILE_URL,
DOWNLOAD_URL,
PARTS_SUPPLIER,
partsSupplierUrl,
IDM_APPROVE_URL,
IDM_LOGOUT_URL,
IAM_LOGIN,
UPDATE_PASSWORD_URL,
ENV_NOTICE
}

271
doc/IAM对接代码参考/router-index.js

@ -0,0 +1,271 @@
import Vue from 'vue'
import Router from 'vue-router'
import { getUrlKey } from "@/utils/getUrlKey.js";
import { Decrypt, Encrypt } from '@/utils/my-aes-crypto.js'
import { getKey } from '../utils/my-aes-crypto';
import http from '@/utils/request'
import Cookies from "js-cookie";
import { pageRoutes, childrenRoutes, moduleRoutes } from '@/router/config'
import {
isURL
} from '@/utils/validate'
import baseUrl from '@/config'
Vue.use(Router)
const router = new Router({
mode: 'hash',
scrollBehavior: () => ({
y: 0
}),
routes: pageRoutes.concat(moduleRoutes)
})
export function addDynamicRoute(routeParams, router) {
// 组装路由名称, 并判断是否已添加, 如是: 则直接跳转
var routeName = routeParams.routeName
var dynamicRoute = window.SITE_CONFIG['dynamicRoutes'].filter(item => item.name === routeName)[0]
if (dynamicRoute) {
return router.push({
name: routeName,
params: routeParams.params
})
}
// 否则: 添加并全局变量保存, 再跳转
dynamicRoute = {
path: routeName,
component: () =>
import(`@/views/modules/${routeParams.path}`),
name: routeName,
meta: {
...window.SITE_CONFIG['contentTabDefault'],
menuId: routeParams.menuId,
title: `${routeParams.title}`
}
}
router.addRoutes([{
...moduleRoutes,
name: `main-dynamic__${dynamicRoute.name}`,
children: [dynamicRoute]
}])
window.SITE_CONFIG['dynamicRoutes'].push(dynamicRoute)
router.push({
name: dynamicRoute.name,
params: routeParams.params
})
}
let appendRoutes = (dataList) => {
for (let i = 0; i < childrenRoutes.length; i++) {
concatRoutes(dataList, childrenRoutes[i]);
}
return dataList;
}
let concatRoutes = (parentList, appendNode) => {
for (let i = 0; i < parentList.length; i++) {
let value = parentList[i];
//向路由的每个结点追加isLastLevel属性,标识是否为最后一级导航结点,按配置到数据库中的算,页面上后append的,默认都是页面内部路由,不算
if (value.children == null) {
value.children = [];
}
if (value.isLastLevel == null || value.isLastLevel == false) {
value.isLastLevel = value.children.length == 0;
}
//依据rootUrl寻找父级结点
if (value.url && appendNode.rootUrl == value.url) { //找到了,为children赋值,结束循环
value.children = value.children.concat(appendNode.children);
return;
} else { //没找到,递归
concatRoutes(value.children, appendNode);
}
}
}
router.beforeEach((to, from, next) => {
var userId = getUrlKey("userId");
var token = getUrlKey("token");
var key = getUrlKey("key");
if (userId && token) {
userId = userId.replace(/\ +/g, "+");//去掉空格
userId = userId.replace(/[ ]/g, "+"); //去掉空格
userId = userId.replace(/[\r\n]/g, "+");//去掉回车换行
token = token.replace(/\ +/g, "+");//去掉空格
token = token.replace(/[ ]/g, "+"); //去掉空格
token = token.replace(/[\r\n]/g, "+");//去掉回车换行
}
var deUserId = "";
var deToken = "";
console.log("userId", userId);
console.log("token", token);
console.log("key", key);
if( Cookies.get('cookieFlag') != '1'){
if (userId && token && key && Number("123" + getKey()) - Number("123" + key) < 600000) {
deUserId = Decrypt(userId, "123" + key, "123" + key);
deToken = Decrypt(token, "123" + key, "123" + key);
console.log("deUserId", deUserId);
console.log("deToken", deToken);
Cookies.set("token", deToken);
Cookies.set("userId", deUserId);
} else {
console.log("已经超时了");
}
}else{
Cookies.remove('cookieFlag');
}
if (to.name != "logout") {
// if (!Cookies.get("token") || !Cookies.get("userId")) {
// window.location.replace(baseUrl.IDM_APPROVE_URL)
// }
}
// 添加动态(菜单)路由
// 已添加或者当前路由为页面路由, 可直接访问
if (window.SITE_CONFIG['dynamicMenuRoutesHasAdded'] || fnCurrentRouteIsPageRoute(to, pageRoutes)) {
return next()
}
// 获取菜单列表, 添加并全局变量保存
http.get(baseUrl.JMPS_ADMIN_URL + '/sys/menu/nav').then(({
data: res
}) => {
console.log("beforeEachbeforeEachbeforeEach");
if (res.code !== 0) {
Vue.prototype.$message({
message: res.msg,
type: "error",
duration: 2000
});
return next({
name: 'login'
})
// window.location.replace(baseUrl.IDM_APPROVE_URL)
}
window.SITE_CONFIG['menuList'] = appendRoutes(res.data);
fnAddDynamicMenuRoutes(window.SITE_CONFIG['menuList'])
next({
...to,
replace: true
})
}).catch(() => {
next({
name: 'login'
})
// window.location.replace(baseUrl.IDM_APPROVE_URL)
})
})
/**
* 判断当前路由是否为页面路由
* @param {*} route 当前路由
* @param {*} pageRoutes 页面路由
*/
function fnCurrentRouteIsPageRoute(route, pageRoutes = []) {
var temp = []
for (var i = 0; i < pageRoutes.length; i++) {
if (route.path === pageRoutes[i].path) {
return true
}
if (pageRoutes[i].children && pageRoutes[i].children.length >= 1) {
temp = temp.concat(pageRoutes[i].children)
}
}
return temp.length >= 1 ? fnCurrentRouteIsPageRoute(route, temp) : false
}
const createRouteConfig = (menu) => {
// 组装路由
var route = {
url: menu.url,
path: '',
component: null,
name: '',
meta: {
...window.SITE_CONFIG['contentTabDefault'],
menuId: menu.id,
title: menu.name
}
}
if (menu.meta && menu.meta.isBreadcrumb) {
route.meta = {
...route.meta,
...menu.meta
}
}
// eslint-disable-next-line
let URL = (menu.url || '').replace(/{{([^}}]+)?}}/g, (s1, s2) => eval(s2)) // URL支持{{ window.xxx }}占位符变量
if (isURL(URL)) {
route['path'] = route['name'] = `i-${menu.id}`
route['meta']['iframeURL'] = URL
} else {
URL = URL.replace(/^\//, '').replace(/_/g, '-')
route['path'] = route['name'] = URL.replace(/\//g, '-')
route['component'] = () =>
import(`@/views/modules/${URL}`)
}
if (menu.routeName && menu.routeName != "") {
route['name'] = menu.routeName;
}
return route;
}
/**
* 添加动态(菜单)路由
* @param {*} menuList 菜单列表
* @param {*} routes 递归创建的动态(菜单)路由
*/
function fnAddDynamicMenuRoutes(menuList = [], routes = []) {
var temp = []
for (var i = 0; i < menuList.length; i++) {
//逻辑需要,对于其下配置了children的结点,本身也要能够跳转
if (menuList[i].url && menuList[i].children && menuList[i].children.length >= 1) {
routes.push(createRouteConfig(menuList[i]));
}
if (menuList[i].children && menuList[i].children.length >= 1) {
temp = temp.concat(menuList[i].children)
continue
}
routes.push(createRouteConfig(menuList[i]))
}
if (temp.length >= 1) {
return fnAddDynamicMenuRoutes(temp, routes)
}
// 添加路由
router.addRoutes([{
...moduleRoutes,
name: 'main-dynamic-menu',
children: routes
},
{
path: '*',
redirect: {
name: '404'
}
}
])
window.SITE_CONFIG['dynamicMenuRoutes'] = routes
window.SITE_CONFIG['dynamicMenuRoutesHasAdded'] = true
}
export default router

BIN
doc/JSD-9647-需求确认书V1.docx

Binary file not shown.

BIN
doc/JSD-9880-需求确认书V1.docx

Binary file not shown.

62
doc/jsd9880.postman_collection测试用例.json

@ -0,0 +1,62 @@
{
"info": {
"_postman_id": "1c37d4fa-6ce7-4829-8a1e-9bc5151032ac",
"name": "jsd9880",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "getToken",
"protocolProfileBehavior": {
"disabledSystemHeaders": {
"user-agent": true,
"accept": true
}
},
"request": {
"method": "POST",
"header": [
{
"key": "Cookie",
"value": "cf_chl_2=8530a6541dd5d4a; cf_chl_prog=x20; cf_clearance=LAn7K16arymRPPFI9SJPfBGWpbln5vCCIZzBrTf_Ibc-1647589093-0-150",
"type": "text"
},
{
"key": "User-Agent",
"value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36 Edg/99.0.1150.39",
"type": "text"
},
{
"key": "accept",
"value": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"type": "text"
}
],
"body": {
"mode": "urlencoded",
"urlencoded": [
{
"key": "accessToken",
"value": "eyJraWQiOiJJZG1Eb21haW4iLCJ4NXQiOiJ6dy1iN0phQlVPQjBrUEtzTlhyOWdHdi0tX3ciLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2lhbXVhdC5mYXdqaWVmYW5nLmNvbS5jbjo0NDMvb2F1dGgyIiwiYXVkIjpbIklkbVJlc1NlcnZlciIsIjE0NzI4MTlhMGNmOTQwYzI5NWY0Yjg0YjFjMDIzMWY1Il0sImV4cCI6MTY0ODEwNTMyMiwianRpIjoiVHFoWTJEcFBQQzdVMWRXbkdqQTBvUSIsImlhdCI6MTY0ODEwMTcyMiwic3ViIjoiMTAwMDQyNjIiLCJzZXNzaW9uSWQiOiIyYmYzYmM1Ny1hN2E5LTQyNjctOWZiZS0xZDU4YTEzYzAzNDN8c2V3dkE4U3F5b3pzNXpuTS9uV2x2a2R6YkNISFNveFpHREpyd3ZSVWhnZz0iLCJjdXN0b21lQXR0ciI6IkN1c3RvbVZhbHVlIiwicmVzU3J2QXR0ciI6IlJFU09VUkNFQ09OU1QiLCJjbGllbnQiOiIxNDcyODE5YTBjZjk0MGMyOTVmNGI4NGIxYzAyMzFmNSIsInNjb3BlIjpbIklkbVJlc1NlcnZlci5Vc2VyUHJvZmlsZS5tZSIsIm9wZW5pZCIsImVtYWlsIiwicGhvbmUiLCJwcm9maWxlIl0sImRvbWFpbiI6IklkbURvbWFpbiJ9.fvcih44HOKTCXEfCOVyxugUHJQDN_d8LqW4TDZX4E3tOaks5skh-JVVci8hOjppPAn6ue1-LWplb6WNxu3qQWsQQdQu6WyRsXsY-2TAqAkDoUs_eLr6FRZkzbjZPSLCq6fpcxTaBCpuWYrHyKCZnpSYw2sjrfcBKY22o4jus4FMxxUOrJowMdzY3CVzy9jqVeX0A0TWwWwgqdMaL6cCNuwnLnmUubs1aGHP-mUdlpNxKJnJlE9YAaRtdBsLaOMpHDgqUsl3EQcBy4R1pbMIiox0_61v433AjhuGIPbjsI-OGTxPJmesIuPi9IXvaB7vxxf0raeT73vBoJGF8kxB6Gw",
"type": "text"
}
]
},
"url": {
"raw": "localhost:8075/webroot/decision/url/getToken",
"host": [
"localhost"
],
"port": "8075",
"path": [
"webroot",
"decision",
"url",
"getToken"
]
}
},
"response": []
}
]
}

BIN
doc/一汽解放_IAM身份管理项目-业务系统登录认证接入规范-v1.5(1).docx

Binary file not shown.

BIN
doc/解放IAM单点登录插件使用文档.docx

Binary file not shown.

BIN
lib/finekit-10.0-20200828.jar

Binary file not shown.

21
plugin.xml

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><plugin>
<id>com.eco.plugin.xxxx.ijf.iam</id>
<name><![CDATA[IAM单点登录]]></name>
<active>yes</active>
<version>1.0.4</version>
<env-version>10.0</env-version>
<jartime>2020-07-31</jartime>
<vendor>fr.open</vendor>
<description><![CDATA[oauth2]]></description>
<change-notes><![CDATA[
add 9880
]]></change-notes>
<extra-decision>
<GlobalRequestFilterProvider class="com.fr.plugin.IAMloginFilter"/>
<!-- 长连接 -->
<HttpHandlerProvider class="com.fr.plugin.TCauth2HandlerProvider"/>
<!-- 短连接 -->
<URLAliasProvider class="com.fr.plugin.TCauth2URLAliasBridge"/>
</extra-decision>
<function-recorder class="com.fr.plugin.TCauth2HandlerProvider"/>
</plugin>

120
src/main/java/com/fr/plugin/GetTicket.java

@ -0,0 +1,120 @@
package com.fr.plugin;
import com.fanruan.api.net.http.HttpKit;
import com.fr.decision.authority.data.User;
import com.fr.decision.fun.impl.BaseHttpHandler;
import com.fr.decision.webservice.v10.login.LoginService;
import com.fr.decision.webservice.v10.user.UserService;
import com.fr.json.JSONObject;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.context.PluginContexts;
import com.fr.third.org.apache.commons.codec.digest.DigestUtils;
import com.fr.third.org.apache.commons.lang3.StringUtils;
import com.fr.third.springframework.web.bind.annotation.RequestMethod;
import com.fr.web.utils.WebUtils;
import org.dom4j.DocumentException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class GetTicket extends BaseHttpHandler {
@Override
public RequestMethod getMethod() {
return null;
}
@Override
public String getPath() {
return "/getToken";
}
@Override
public boolean isPublic() {
return true;
}
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
JSONObject entries = new JSONObject();
if (!PluginContexts.currentContext().isAvailable()) {
entries.put("code", "1");
entries.put("msg", "授权过期请联系销售人员");
WebUtils.printAsJSON(httpServletResponse, entries);
return;
}
String accessToken = WebUtils.getHTTPRequestParameter(httpServletRequest, "accessToken");
if (StringUtils.isBlank(accessToken)) {
entries.put("code", "1");
entries.put("msg", "accessToken码不存在");
WebUtils.printAsJSON(httpServletResponse, entries);
return;
}
//第一步获取token
// String accessToken = getAccessToken(code);
// if (StringUtils.isBlank(accessToken)) {
// entries.put("code", "1");
// entries.put("msg", "授权码无效,请重新授权");
// WebUtils.printAsJSON(httpServletResponse, entries);
// return;
// }
String uid = getUserInfo(accessToken);
User user = UserService.getInstance().getUserByUserName(uid);
if (user == null) {
entries.put("code", "1");
entries.put("msg", "登录失败:" + uid + " 在帆软用户体系不存在,请联系管理员添加");
WebUtils.printAsJSON(httpServletResponse, entries);
return;
}
String token = login(httpServletRequest, httpServletResponse, uid);
entries.put("code", "0");
entries.put("data", token);
WebUtils.printAsJSON(httpServletResponse, entries);
}
private String getAccessToken(String code) throws IOException {
Oauth2Config config = Oauth2Config.getInstance();
String valAddr = config.getValAddr();
String appId = config.getAppId();
String clientSecret = config.getClientSecret();
String frUrl = Oauth2Config.getInstance().getFrUrl();
String redirectUrl = String.format("%s/url/iam/authCallBack", frUrl);
Map<String, String> params = new HashMap<>();
String tokenUrl = String.format("%s/oauth2/rest/token", valAddr);
params.put("redirect_uri", redirectUrl);
params.put("grant_type", "AUTHORIZATION_CODE");
params.put("code", code);
Map<String, String> header = new HashMap<>();
header.put("X-OAUTH-IDENTITY-DOMAIN-NAME", "IdmDomain");
header.put("Authorization", "Basic " + Base64.getEncoder().encodeToString(String.format("%s:%s", appId, clientSecret).getBytes(StandardCharsets.UTF_8)));
String json = HttpKit.post(tokenUrl, params, "utf-8", "utf-8", header);
FineLoggerFactory.getLogger().info("获取AccessToken 请求返回:{}", json);
JSONObject obj = new JSONObject(json);
return obj.getString("access_token");
}
public static String getUserInfo(String accessToken) throws DocumentException, IOException {
Map<String, String> header = new HashMap<>();
Oauth2Config config = Oauth2Config.getInstance();
String valAddr = config.getValAddr();
String url = String.format("%s/oauth2/rest/userinfo?access_token=%s", valAddr, accessToken);
header.put("Authorization", "Bearer " + accessToken);
String json = HttpKit.get(url, new HashMap<>(), header);
FineLoggerFactory.getLogger().info("获取userinfo 请求返回:{}", json);
JSONObject obj = new JSONObject(json);
return obj.getString("sub");
}
private String login(HttpServletRequest req, HttpServletResponse res, String username) throws Exception {
String token = LoginService.getInstance().login(req, res, username);
req.setAttribute("fine_auth_token", token);
FineLoggerFactory.getLogger().info("fr FrFilter is over with username is ###" + username);
return token;
}
}

63
src/main/java/com/fr/plugin/GoAuthApi.java

@ -0,0 +1,63 @@
package com.fr.plugin;
import com.fr.decision.fun.impl.BaseHttpHandler;
import com.fr.decision.webservice.v10.login.LoginService;
import com.fr.third.org.apache.commons.codec.digest.DigestUtils;
import com.fr.third.org.apache.commons.lang3.StringUtils;
import com.fr.third.springframework.web.bind.annotation.RequestMethod;
import com.fr.web.utils.WebUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
public class GoAuthApi extends BaseHttpHandler {
@Override
public RequestMethod getMethod() {
return null;
}
@Override
public String getPath() {
return "/goAuth";
}
@Override
public boolean isPublic() {
return true;
}
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
if (isLogin(httpServletRequest)) {
sendRedirect(httpServletResponse, HttpUtils.getDefaultUrl(httpServletRequest));
return;
} else {
String valAddr = Oauth2Config.getInstance().getValAddr();
String appId = Oauth2Config.getInstance().getAppId();
String frUrl = Oauth2Config.getInstance().getFrUrl();
String redirectUrl = String.format("%s/url/iam/authCallBack", frUrl);
redirectUrl = URLEncoder.encode(redirectUrl, "utf-8");
String goUrl = String.format("%s/oauth2/rest/authz?response_type=code&client_id=%s&domain=IdmDomain&state=xyz&scope=IdmResServer.UserProfile.me openid email phone profile&redirect_uri=%s", valAddr, appId, redirectUrl);
sendRedirect(httpServletResponse, goUrl);
}
}
private void sendRedirect(HttpServletResponse res, String url) throws IOException {
Map<String, String> params = new HashMap<>();
params.put("callBack", url);
WebUtils.writeOutTemplate("com/fr/plugin/redirect.html", res, params);
}
private boolean isLogin(HttpServletRequest req) {
return LoginService.getInstance().isLogged(req);
}
private String md5(String str) {
return DigestUtils.md5Hex(str);
}
}

52
src/main/java/com/fr/plugin/HttpUtils.java

@ -0,0 +1,52 @@
package com.fr.plugin;
import com.fr.base.FRContext;
import com.fr.base.ServerConfig;
import com.fr.base.TemplateUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
import com.fr.third.org.apache.commons.io.IOUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* http请求工具类
*
* @author 0246
*/
public class HttpUtils {
/**
* 返回当前系统的根路径
*
* @return
*/
public static String getDefaultUrl(HttpServletRequest req) {
StringBuilder url = new StringBuilder();
try {
url.append(req.getScheme());
url.append("://");
url.append(req.getServerName());
if (req.getServerPort() != 80) {
url.append(":");
url.append(req.getServerPort());
}
url.append(TemplateUtils.render("${fineServletURL}"));
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
return url.toString();
}
}

166
src/main/java/com/fr/plugin/IAMloginFilter.java

@ -0,0 +1,166 @@
package com.fr.plugin;
import com.fr.base.ServerConfig;
import com.fr.base.TemplateUtils;
import com.fr.data.NetworkHelper;
import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider;
import com.fr.decision.webservice.utils.DecisionStatusService;
import com.fr.decision.webservice.v10.login.LoginService;
import com.fr.json.JSONObject;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.transform.ExecuteFunctionRecord;
import com.fr.plugin.transform.FunctionRecorder;
import com.fr.stable.StringUtils;
import com.fr.store.StateHubService;
import com.fr.web.utils.WebUtils;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.Map;
@FunctionRecorder(localeKey = "fds")
public class IAMloginFilter extends AbstractGlobalRequestFilterProvider {
@Override
public String filterName() {
return "oauth2";
}
@Override
public String[] urlPatterns() {
return new String[]{
"/*"
};
}
@Override
public void init(FilterConfig filterConfig) {
Oauth2Config.getInstance();
super.init(filterConfig);
}
@Override
@ExecuteFunctionRecord
public void doFilter(HttpServletRequest request, HttpServletResponse httpServletResponse, FilterChain filterChain) {
try {
if (isLogOut(request)) {
delLoginOut(request, httpServletResponse);
return;
}
if (needFilter(request) && !isLogin(request)) {
//跳转到登录界面
String originalURL =getOriginalUrlIgnoreCode(request);
String frUrl = Oauth2Config.getInstance().getFrUrl();
String valAddr = Oauth2Config.getInstance().getValAddr();
String appId = Oauth2Config.getInstance().getAppId();
StateHubService stateHubService = DecisionStatusService.originUrlStatusService();
stateHubService.put("loginCallBack", originalURL);
String redirectUrl = String.format("%s/url/iam/authCallBack", frUrl);
redirectUrl = URLEncoder.encode(redirectUrl, "utf-8");
String goUrl = String.format("%s/oauth2/rest/authz?response_type=code&client_id=%s&domain=IdmDomain&state=xyz&scope=IdmResServer.UserProfile.me openid email phone profile&redirect_uri=%s", valAddr, appId, redirectUrl);
sendRedirect(httpServletResponse, goUrl);
return;
}
filterChain.doFilter(request, httpServletResponse);
} catch (IOException | ServletException e) {
printException2FrLog(e);
} catch (Exception e) {
printException2FrLog(e);
}
}
public String getOriginalUrlIgnoreCode(HttpServletRequest request) throws Exception {
StringBuffer url = new StringBuffer(request.getRequestURI());
Map parameterMap = request.getParameterMap();
Iterator iterator = parameterMap.entrySet().iterator();
boolean notFirst = url.toString().indexOf("?") == -1;
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
if (StringUtils.equals("code", entry.getKey().toString())) {
continue;
}
if (notFirst) {
url.append('?');
notFirst = false;
} else {
url.append('&');
}
url.append(entry.getKey().toString());
url.append('=');
url.append( URLEncoder.encode(request.getParameter(entry.getKey().toString()),"utf-8"));
}
FineLoggerFactory.getLogger().info("重定向到:" + url.toString());
return url.toString();
}
private void delLoginOut(HttpServletRequest req, HttpServletResponse res) {
try {
//执行帆软内部的退出
LoginService.getInstance().logout(req, res);
Oauth2Config oauth2Config = Oauth2Config.getInstance();
JSONObject jsonObject = new JSONObject();
String url = String.format("%s/xxxx/ssoLoginService/goLogout", oauth2Config.getValAddr());
jsonObject.put("data", url);
//调用外部接口注销accessToken
FineLoggerFactory.getLogger().error("登出成功: ----------------");
//指定退出之后到他们登录页面
WebUtils.printAsJSON(res, jsonObject);
} catch (Exception var4) {
}
}
private boolean isLogOut(HttpServletRequest req) {
String url = WebUtils.getOriginalURL(req);
String servletNamePrefix = "/" + ServerConfig.getInstance().getServletName() + "/logout";
return url.contains(servletNamePrefix) && req.getMethod().equals("POST");
}
private void sendRedirect(HttpServletResponse res, String url) {
res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
res.setHeader("Location", url);
}
private boolean needFilter(HttpServletRequest request) {
String requestURI = request.getRequestURI();
String isAdmin = request.getParameter("isAdmin");
if (StringUtils.equals(isAdmin, "1")) {
return false;
}
if (StringUtils.isNotBlank(requestURI) && request.getMethod().equals("GET")) {
if (requestURI.endsWith("decision")) {
return true;
}
if (requestURI.endsWith("/view/form") || requestURI.endsWith("/view/report")) {
if (StringUtils.isNotBlank(request.getParameter("viewlet"))) {
return true;
}
}
if (requestURI.contains("/v10/entry/access/") && request.getMethod().equals("GET")) {
return true;
}
if (requestURI.contains("/v5/design/report") && (requestURI.endsWith("/edit") || requestURI.endsWith("/view"))) {
return true;
}
}
return false;
}
public static void printException2FrLog(Throwable e) {
StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
String s = writer.toString();
FineLoggerFactory.getLogger().error("错误:{}", s);
}
private boolean isLogin(HttpServletRequest req) {
return LoginService.getInstance().isLogged(req);
}
}

70
src/main/java/com/fr/plugin/Oauth2Config.java

@ -0,0 +1,70 @@
package com.fr.plugin;
import com.fr.config.*;
import com.fr.config.holder.Conf;
import com.fr.config.holder.factory.Holders;
@Visualization(category = "IAM单点登录配置")
public class Oauth2Config extends DefaultConfiguration {
private static volatile Oauth2Config config = null;
public static Oauth2Config getInstance() {
if (config == null) {
config = ConfigContext.getConfigInstance(Oauth2Config.class);
}
return config;
}
@Identifier(value = "valAddr", name = "接口地址", description = "接口地址", status = Status.SHOW)
private Conf<String> valAddr = Holders.simple("");
@Identifier(value = "frUrl", name = "报表地址", description = "报表地址", status = Status.SHOW)
private Conf<String> frUrl = Holders.simple("http://localhost:8075/webroot/decision");
@Identifier(value = "appId", name = "clientId", description = "clientId", status = Status.SHOW)
private Conf<String> appId = Holders.simple("");
@Identifier(value = "clientSecret", name = "clientSecret", description = "clientSecret", status = Status.SHOW)
private Conf<String> clientSecret = Holders.simple("");
public String getFrUrl() {
return frUrl.get();
}
public void setFrUrl(String frUrl) {
this.frUrl.set(frUrl);
}
public String getAppId() {
return appId.get();
}
public void setAppId(String appId) {
this.appId.set(appId);
}
public String getClientSecret() {
return clientSecret.get();
}
public void setClientSecret(String clientSecret) {
this.clientSecret.set(clientSecret);
}
public String getValAddr() {
return valAddr.get();
}
public void setValAddr(String valAddr) {
this.valAddr.set(valAddr);
}
@Override
public Object clone() throws CloneNotSupportedException {
Oauth2Config cloned = (Oauth2Config) super.clone();
cloned.valAddr = (Conf<String>) valAddr.clone();
cloned.appId = (Conf<String>) appId.clone();
cloned.clientSecret = (Conf<String>) clientSecret.clone();
cloned.frUrl = (Conf<String>) frUrl.clone();
return cloned;
}
}

122
src/main/java/com/fr/plugin/TCAuthCallbackApi.java

@ -0,0 +1,122 @@
package com.fr.plugin;
import com.fanruan.api.net.http.HttpKit;
import com.fr.decision.authority.data.User;
import com.fr.decision.fun.impl.BaseHttpHandler;
import com.fr.decision.webservice.utils.DecisionStatusService;
import com.fr.decision.webservice.v10.login.LoginService;
import com.fr.decision.webservice.v10.user.UserService;
import com.fr.json.JSONObject;
import com.fr.log.FineLoggerFactory;
import com.fr.store.StateHubService;
import com.fr.third.jodd.util.StringUtil;
import com.fr.third.org.apache.commons.lang3.StringUtils;
import com.fr.third.springframework.web.bind.annotation.RequestMethod;
import com.fr.web.utils.WebUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class TCAuthCallbackApi extends BaseHttpHandler {
@Override
public RequestMethod getMethod() {
return null;
}
@Override
public String getPath() {
return "/authCallBack";
}
@Override
public boolean isPublic() {
return true;
}
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
String code = WebUtils.getHTTPRequestParameter(httpServletRequest, "code");
if (StringUtils.isBlank(code)) {
WebUtils.printAsString(httpServletResponse, "code授权码不存在");
return;
}
//第一步获取token
String accessToken = getAccessToken(code);
if (StringUtils.isBlank(accessToken)) {
WebUtils.printAsString(httpServletResponse, "授权码无效,请重新授权");
return;
}
String uid = getUserInfo(accessToken);
User user = UserService.getInstance().getUserByUserName(uid);
if (user == null) {
WebUtils.printAsString(httpServletResponse, "登录失败:" + uid + " 在帆软用户体系不存在,请联系管理员添加");
return;
}
login(httpServletRequest, httpServletResponse, uid);
StateHubService stateHubService = DecisionStatusService.originUrlStatusService();
Object callback = stateHubService.get("loginCallBack");
if (callback != null) {
sendRedirect(httpServletResponse, callback.toString());
return;
}
sendRedirect(httpServletResponse, HttpUtils.getDefaultUrl(httpServletRequest));
}
private String getAccessToken(String code) throws IOException {
Oauth2Config config = Oauth2Config.getInstance();
String valAddr = config.getValAddr();
String appId = config.getAppId();
String clientSecret = config.getClientSecret();
String frUrl = Oauth2Config.getInstance().getFrUrl();
String redirectUrl = String.format("%s/url/iam/authCallBack", frUrl);
Map<String, String> params = new HashMap<>();
String tokenUrl = String.format("%s/oauth2/rest/token", valAddr);
params.put("redirect_uri", redirectUrl);
params.put("grant_type", "AUTHORIZATION_CODE");
params.put("code", code);
Map<String, String> header = new HashMap<>();
header.put("X-OAUTH-IDENTITY-DOMAIN-NAME", "IdmDomain");
header.put("Authorization", "Basic " + Base64.getEncoder().encodeToString(String.format("%s:%s", appId, clientSecret).getBytes(StandardCharsets.UTF_8)));
String json = HttpKit.post(tokenUrl, params, "utf-8", "utf-8", header);
FineLoggerFactory.getLogger().info("获取AccessToken 请求返回:{}", json);
JSONObject obj = new JSONObject(json);
return obj.getString("access_token");
}
public static String getUserInfo(String accessToken) throws DocumentException, IOException {
Map<String, String> header = new HashMap<>();
Oauth2Config config = Oauth2Config.getInstance();
String valAddr = config.getValAddr();
String url = String.format("%s/oauth2/rest/userinfo?access_token=%s", valAddr, accessToken);
header.put("Authorization", "Bearer " + accessToken);
String json = HttpKit.get(url, new HashMap<>(), header);
FineLoggerFactory.getLogger().info("获取userinfo 请求返回:{}", json);
JSONObject obj = new JSONObject(json);
return obj.getString("sub");
}
private String login(HttpServletRequest req, HttpServletResponse res, String username) throws Exception {
String token = LoginService.getInstance().login(req, res, username);
req.setAttribute("fine_auth_token", token);
FineLoggerFactory.getLogger().info("fr FrFilter is over with username is ###" + username);
return token;
}
private void sendRedirect(HttpServletResponse res, String url) throws IOException {
Map<String, String> params = new HashMap<>();
params.put("callBack", url);
WebUtils.writeOutTemplate("com/fr/plugin/redirect.html", res, params);
}
}

25
src/main/java/com/fr/plugin/TCauth2HandlerProvider.java

@ -0,0 +1,25 @@
package com.fr.plugin;
import com.fr.decision.fun.HttpHandler;
import com.fr.decision.fun.impl.AbstractHttpHandlerProvider;
import com.fr.plugin.transform.ExecuteFunctionRecord;
import com.fr.plugin.transform.FunctionRecorder;
import com.fr.stable.fun.Authorize;
@FunctionRecorder
/**
* url处理器需要在这里注册
*/
@Authorize
public class TCauth2HandlerProvider extends AbstractHttpHandlerProvider {
@Override
@ExecuteFunctionRecord
public HttpHandler[] registerHandlers() {
return new HttpHandler[]{
new GoAuthApi(),
new GetTicket(),
new TCAuthCallbackApi()
};
}
}

27
src/main/java/com/fr/plugin/TCauth2URLAliasBridge.java

@ -0,0 +1,27 @@
package com.fr.plugin;
import com.fr.decision.fun.impl.AbstractURLAliasProvider;
import com.fr.decision.webservice.url.alias.URLAlias;
import com.fr.decision.webservice.url.alias.URLAliasFactory;
/**
* 将长连接转换为短连接
* 参考文档
* https://wiki.fanruan.com/display/PD/com.fr.decision.fun.URLAliasProvider
*/
public class TCauth2URLAliasBridge extends AbstractURLAliasProvider
{
public TCauth2URLAliasBridge() {
Oauth2Config.getInstance();
}
@Override
public URLAlias[] registerAlias() {
//像这样配置之后再访问/api就可以通过http(s)://ip:port/webroot/decision/url/api。 进行访问
return new URLAlias[]{
URLAliasFactory.createPluginAlias("/goAuth", "/goAuth", true),
URLAliasFactory.createPluginAlias("/getToken", "/getToken", true),
URLAliasFactory.createPluginAlias("/iam/authCallBack", "/authCallBack", true),
};
}
}

11
src/main/resources/com/fr/plugin/redirect.html

@ -0,0 +1,11 @@
<!doctype html>
<html lang="en">
<head>
<script type="text/javascript">
window.location.href = '${callBack}';
</script>
</head>
<body>
<!--<h3>登陆成功${loginUser},5秒后跳转到:${callBack}</h3>-->
</body>
</html>
Loading…
Cancel
Save