---
order: 4
---
# 开发IP授信应用

SuccBI可以配置信任第三方系统所在的IP地址，从而让第三方系统有权限访问SuccBI的api接口，比如获取登录令牌的api接口从而实现单点登录。

- [将SuccBI页面嵌入到第三方系统](#embed)
  - [java代码示例](#java-code)
- [第三方系统远程调用SuccBI API](#rc)
  - [HTTP请求封装java示例](#java-http)

## 将SuccBI页面嵌入到第三方系统{#embed}

当将SuccBI页面通过iframe嵌入到第三方页面（需要考虑[跨域](./embed-into-3rd.md#cors)）或者作为一个被点击跳转的链接时，希望能在打开SuccBI页面后，能让用户免登录访问SuccBI页面。开发步骤：

1. 在SuccBI中注册一个[IP授信应用](../../sys-settings/security/trustedapps.md#trust-ip)。
2. 在第三方系统中准备一个action用于控制重定向到SuccBI。
3. 在action中发送HTTP请求到[SuccBI认证接口](../references/web-api/oauth2/getToken.md)，请求登录令牌access\_token（有效期两个小时，没有使用次数限制，请妥善保存）。
4. 使用登录令牌来[换取临时登录用的access\_token](../references/web-api/me/getAccessToken.md)，这个access\_token有效期10分钟，并且只能用一次。
5. 将请求到的临时登录令牌access\_token作为参数放到需要访问SuccBI的url中。

::: tip
第二步生成的登录令牌access\_token也可以用来登录，但是有效时间比较长，并且不是一次性的，如果放到浏览器URL上泄露出去可能会导致严重的安全问题，这个令牌更适用于[第三方系统远程调用SuccBI API](#rc)。
:::

### java代码示例{#java-code}

::: details 点击展开查看代码>>

```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{#rc}

多个业务系统的数据信息都是分开存储的，第三方系统会有需要依赖于SuccBI去获取数据，以及通知SuccBI去更改数据状态，通过服务器远程调用API的方式会比较安全可靠。开发步骤有：

1. 在SuccBI中注册一个[IP授信应用](../../sys-settings/security/trustedapps.md#trust-ip)。
2. 第三方系统服务器发送HTTP请求到[SuccBI认证接口](../references/web-api/oauth2/getToken.md)，请求授权令牌access\_token（有效期两个小时，没有使用次数限制，请妥善保存）。
3. 第三方系统服务器访问SuccBI API，并在url带上参数`access_token`(值取第二步获取到的授权令牌)。

::: tip

第三步中使用access\_token访问SuccBI API时，如果发送的是一个`GET`请求，SuccBI会响应`302`，并在响应头中添加session的设置（响应头Set-Cookie: JSESSIONID=xxx）和[Location](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Location)。第三方系统在接收到这个`302`响应后，需要再次发送请求到响应头Location指定的url地址，并在响应头中带上session（请求头Cookie：JSESSIONID=xxx）才能真正成功调用这个API。

**如果使用`java`来构建第三方系统，建议使用[HttpClient](https://mvnrepository.com/search?q=HttpClient)来构建Http请求**，它提供了关于重定向和session管理机制，示例代码请参考：[http请求封装](#java-code-http)。

::: details 点击展开查看HTTP请求与响应示例>>

- 发送GET请求：

```bash
GET https://example.succbi.com/api/getData.action?access_token=asedr6t7fy8gu
```

- SuccBI响应头：

```bash
Location: https://example.succbi.com/api/getData.action
Set-Cookie: JSESSIONID=09B5A06481A3085B5332823BA591DA5F; Path=/; Secure; HttpOnly; SameSite=None
```

- 第三方系统再次发送请求:

```bash
GET https://example.succbi.com/api/getData.action

Cookie: JSESSIONID=09B5A06481A3085B5332823BA591DA5F
```

:::

### HTTP请求封装java示例{#java-http}

::: details 点击展开查看代码>>

```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 {
		HttpClientContext 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");
		}
	}
}

```

:::
