简体中文
Groovy代码示例
约 870 字大约 3 分钟
2026-01-09
class OauthServiceImpl implements AuthProviderPlugin {
/**
* 登录时打开 {租户域名}.my.fxiaoke.com 跳转的第三方url
*/
@Override
String authorize(FunctionContext context, Map<String, List<String>> params) {
//返回给浏览器的第三方网站登录地址,具体参数内容请查阅第三方文档说明
return "https://www.otherdomain.com/oauth2/auth?" + "response_type=code&" +
"response_mode=query&" +
"scope=openid&" +
"redirect_uri={租户域名}.my.fxiaoke.com/oauth2/sp/callback/{URL后缀}" + //第三方登录后的回调地址
"client_id={第三方应用ID}";
}
/**
* 第三方登录完成后的回调函数,一般用于获取用户信息
* @param params 第三方回调时,URL的参数
* @return 返回纷享系统的员工ID
*/
@Override
Integer callback(FunctionContext context, Map<String, List<String>> params) {
//租户临时授权模式,如果有其他模式,请阅读第三方文档
String token = getAccessToken(params);
log.info(token);
//从人员对象,获取纷享用户userId
Integer userId = openId2userId(token);
log.info(userId);
return userId;
}
/**
* 登录成功后打开的页面,可以从params获取,或者指定一个页面,空则是打开默认的页面
* @return 登录成功后打开的URL
*/
@Override
String redirect(FunctionContext context, Map<String, List<String>> params) {
// encode意思是需要进行url编码,让参数符合url规范,下面把这个过程简化为encode(内容)
// 请求参数为 ?target=encode(/XV/UI/Home),则使用 params.get("target").get(0) 进行返回,租户对应域名会自动拼上
// 请求参数为 ?target=encode(https://www.fxiaoke.com/XV/UI/Home),则使用 params.get("target").get(0) 进行返回,直接会302到对应地址
// 请求参数为 ?target=encode(/hcrm/avah5/function/todo?id=xxx&apiName=xxxx) 则会根据打开的浏览器自动识别,打开web或者h5端(该功能目前灰度中)
// 返回null或者"",则打开默认的首页
// 编写代码,需要考虑target可能不存在的情况
// target只是举例说明并非规范,可以按照对方协议来更换变量名称
// params国际规范上是数组,但一般情况下默认取第0个就好
if (params.containsKey("target")) {
return params.get("target").get(0)
} else {
return null;
}
}
/**
* 在纷享系统登出时,自动跳转到第三方系统登出地址
* @return 第三方登录地址,如无需登出第三方,请返回null
*/
@Override
String logoffUrl(FunctionContext context) {
return "https://www.otherdomain.com/oauth2/logoff"
}
String getAccessToken(Map<String, List<String>> parameterMap) {
//以某第三方为示意,具体请查看第三方登录文档
FormBody body = FormBody.builder()
.field("client_id", { 第三方应用ID })
.field("scope", "openid")
.field("redirect_uri", "https://xxx.my.fxiaoke.com/oauth2/sp/callback/xxx")
.field("client_secret", { 第三方应用密码 })
.field("code", parameterMap["code"].get(0))
.build()
Request request = Request.builder()
.method("POST")
.url("https://xxxx/oauth2/token")
.timeout(7000)
.retryCount(0)
.body(body)
.build()
HttpResult o = (HttpResult) http.execute(request).getData()
log.info(o)
return o.content["access_token"] as String
}
Integer openId2userId(String accessToken) {
//获取第三方用户信息
HttpResult o = (HttpResult) http.get("https://xxx/oauth2/userinfo", ["Authorization": accessToken]).getData();
String user = o.content["sub"] as String
log.info(user)
//从第三方用户信息里,查询人员对象获取绑定信息,建议用自定义字段
APIResult data = Fx.object.find("PersonnelObj", //查询客户对象
FQLAttribute.builder()
.columns(["user_id"]) //返回的数据id
.queryTemplate(QueryTemplate.AND(["UserDefineField__c": QueryOperator.EQ(user)]))
.build(),
SelectAttribute.builder()
.build());
if(data.isError()){
message.throwErrorMessage("获取客户信息异常: " + data.message())
}
List<Map> dataList = data.dataList
//如果用户信息查找失败,返回错误
//也可以在此根据信息,进行新建人员并且设置绑定字段的内容
if (dataList.size() <= 0) {
message.throwErrorMessage("找不到对应的用户, user:" + user)
}
if (dataList.size() > 1) {
message.throwErrorMessage("找到多个对应的用户, user:" + user)
}
//返回员工对象中的user_id字段,用于后续登录时使用
return dataList[0]["user_id"].toString() as Integer
}
//debug 时候的入口方法
void debug(FunctionContext context, Map arg) {
}
}