# 开发IP授信应用

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

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

当将SuccBI页面通过iframe嵌入到第三方页面(需要考虑跨域)或者作为一个被点击跳转的链接时,希望能在打开SuccBI页面后,能让用户免登录访问SuccBI页面。开发步骤:

  1. 在SuccBI中注册一个IP授信应用
  2. 在第三方系统中准备一个action用于控制重定向到SuccBI。
  3. 在action中发送HTTP请求到SuccBI认证接口,请求登录令牌access_token(有效期两个小时,没有使用次数限制,请妥善保存)。
  4. 使用登录令牌来换取临时登录用的access_token,这个access_token有效期10分钟,并且只能用一次。
  5. 将请求到的临时登录令牌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的方式会比较安全可靠。开发步骤有:

  1. 在SuccBI中注册一个IP授信应用
  2. 第三方系统服务器发送HTTP请求到SuccBI认证接口,请求授权令牌access_token(有效期两个小时,没有使用次数限制,请妥善保存)。
  3. 第三方系统服务器访问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条评论
评论