# 开发IP授信应用
SuccBI可以配置信任第三方系统所在的IP地址,从而让第三方系统有权限访问SuccBI的api接口,比如获取登录令牌的api接口从而实现单点登录。
# 将SuccBI页面嵌入到第三方系统
当将SuccBI页面通过iframe嵌入到第三方页面(需要考虑跨域)或者作为一个被点击跳转的链接时,希望能在打开SuccBI页面后,能让用户免登录访问SuccBI页面。开发步骤:
- 在SuccBI中注册一个IP授信应用。
- 在第三方系统中准备一个action用于控制重定向到SuccBI。
- 在action中发送HTTP请求到SuccBI认证接口,请求登录令牌access_token(有效期两个小时,没有使用次数限制,请妥善保存)。
- 使用登录令牌来换取临时登录用的access_token,这个access_token有效期10分钟,并且只能用一次。
- 将请求到的临时登录令牌access_token作为参数放到需要访问SuccBI的url中。
TIP
第二步生成的登录令牌access_token也可以用来登录,但是有效时间比较长,并且不是一次性的,如果放到浏览器URL上泄露出去可能会导致严重的安全问题,这个令牌更适用于第三方系统远程调用SuccBI API。
# java代码示例
点击展开查看代码>>
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
public class SSOAction {
@RequestMapping("/sso")
public void ssoRedirect(String redirect_uri, HttpServletResponse response) throws IOException {
String userid = ""; // 请替换为需要登录的用户id,这个用户要在SuccBI 系统用户表中村子
String app_id = ""; // 请替换为IP授信应用ID
String app_secret = ""; // 请替换为IP授信应用秘钥
response.sendRedirect(
redirect_uri + "?access_token=" + URLEncoder.encode(getAccessToken(userid, app_id, app_secret),
"UTF-8"));
}
/**
* 向SuccBI服务器请求登录令牌access_token
*
* @param userid 需要登录的用户id
* @param app_id IP授信应用ID
* @param app_secret IP授信应用秘钥
* @return
* @throws IOException
*/
public String getAccessToken(String userid, String app_id, String app_secret) throws IOException {
Map<String, Object> params = new HashMap<>();
params.put("app_id", app_id);
params.put("app_secret", app_secret);
params.put("grant_type", "ip");// 请必要填写为 “ip”
params.put("userid", userid);
/*
* 这里发送http post 请求到SuccBI系统后台api获取access_token,params为参数,需要被序列化为json格式传输数据
*
* - 请替换 https://example.succbi.com 为SuccBI系统部署地址
* - 发送请求方法代码可参考:https://docs.succbi.com/dev/ip-token#java-http
*/
@SuppressWarnings("unchecked") Map<String, Object> result = new ObjectMapper().readValue(
WebUtils.post("https://example.succbi.com/api/oauth2/getToken", params), Map.class);
String access_token = (String) result.get("access_token");
/*
* 这里发送个post请求,请求SuccBI后台api,换取临时登录access_token
*/
return WebUtils.post(
"https://example.succbi.com/api/auth/getAccessToken?access_token=" + URLEncoder.encode(access_token,
"UTF-8"), null);
}
}
# 第三方系统远程调用SuccBI API
多个业务系统的数据信息都是分开存储的,第三方系统会有需要依赖于SuccBI去获取数据,以及通知SuccBI去更改数据状态,通过服务器远程调用API的方式会比较安全可靠。开发步骤有:
- 在SuccBI中注册一个IP授信应用。
- 第三方系统服务器发送HTTP请求到SuccBI认证接口,请求授权令牌access_token(有效期两个小时,没有使用次数限制,请妥善保存)。
- 第三方系统服务器访问SuccBI API,并在url带上参数
access_token
(值取第二步获取到的授权令牌)。
TIP
第三步中使用access_token访问SuccBI API时,如果发送的是一个GET
请求,SuccBI会响应302
,并在响应头中添加session的设置(响应头Set-Cookie: JSESSIONID=xxx)和Location (opens new window)。第三方系统在接收到这个302
响应后,需要再次发送请求到响应头Location指定的url地址,并在响应头中带上session(请求头Cookie:JSESSIONID=xxx)才能真正成功调用这个API。
如果使用java
来构建第三方系统,建议使用HttpClient (opens new window)来构建Http请求,它提供了关于重定向和session管理机制,示例代码请参考:http请求封装。
点击展开查看HTTP请求与响应示例>>
- 发送GET请求:
GET https://example.succbi.com/api/getData.action?access_token=asedr6t7fy8gu
- SuccBI响应头:
Location: https://example.succbi.com/api/getData.action
Set-Cookie: JSESSIONID=09B5A06481A3085B5332823BA591DA5F; Path=/; Secure; HttpOnly; SameSite=None
- 第三方系统再次发送请求:
GET https://example.succbi.com/api/getData.action
Cookie: JSESSIONID=09B5A06481A3085B5332823BA591DA5F
# HTTP请求封装java示例
点击展开查看代码>>
import com.fasterxml.jackson.databind.ObjectMapper;
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.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.util.Map;
public class WebUtils {
/**
* 为访问SuccBI api指定了请求上下文
*
* 上下文中会记录cookie的使用,以方便正确的使用cookie-session机制,减少访问SuccBI产生的多余session资源
*/
private static HttpClientContext context;
private static final ObjectMapper objectMapper = new ObjectMapper();
static {
context = HttpClientContext.create();
context.setRequestConfig(RequestConfig.custom()
.setConnectTimeout(15000)
.setRedirectsEnabled(true)// 允许处理重定向
.setConnectionRequestTimeout(5000)
.setSocketTimeout(15000)
.build()
);
}
/**
* 获取一个http link的内容当做字符串返回
*
* @param url
* @return http响应主体字符串
* @throws IOException
*/
public static String wget(String url) throws IOException {
CloseableHttpClient client = HttpClients.createDefault();
HttpGet get = new HttpGet(url);
try (CloseableHttpResponse response = client.execute(get, context)) {
return EntityUtils.toString(response.getEntity(), "UTF-8");
}
}
/**
* 向一个http link 发送post请求,参数将使用json形式表示,把响应主体当作字符串返回
*
* @param url
* @param params 参数列表
* @return http响应主体字符串
* @throws IOException
*/
public static String post(String url, Map<String, Object> params) throws IOException {
CloseableHttpClient client = HttpClients.createDefault();
HttpPost post = new HttpPost(url);
post.setEntity(new StringEntity(objectMapper.writeValueAsString(params), "UTF-8"));
post.setHeader("Content-Type", "application/json; charset=UTF-8");
try (CloseableHttpResponse response = client.execute(post)) {
return EntityUtils.toString(response.getEntity(), "UTF-8");
}
}
}
0条评论
评论