# 使用 sync\_sso 同步 DiscourseConnect 用户数据 \[Java\]

**URL:** <https://www.isharkfly.com/t/sync-sso-discourseconnect-java/15790>\
**Category:** Discourse\
**Tags:** java, discourse\
**Created:** [May 24, 2024, 12:20am UTC](https://www.isharkfly.com/t/sync-sso-discourseconnect-java/15790 "2024-05-24T00:20:58Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![honeymoose](https://www.isharkfly.com/user_avatar/www.isharkfly.com/honeymoose/32/20796_2.png) [@honeymoose](https://www.isharkfly.com/u/honeymoose)\
**Post date:** [May 24, 2024, 12:20am UTC](https://www.isharkfly.com/t/sync-sso-discourseconnect-java/15790/1 "2024-05-24T00:20:58Z")

</div>

最近有一个使用 SSO 把已有的用户同步到 Discourse 的需求。

所以，我就根据官方针对 PHP 实现（[Sync DiscourseConnect user data with the sync\_sso route - Integrations - Discourse Meta](https://meta.discourse.org/t/sync-discourseconnect-user-data-with-the-sync-sso-route/84398) ）写了一个有关 Java 的实现。

实现的方法很简单，但是需要用到一些额外的包，最重要的是 Apache commons codec 和 Okhttp。

Apache commons codec 是用来生成数字签名的，Okhttp 是用来发送 Http Post 请求的。

## 设置相关的参数

这里有 4 个参数需要提前获得。

获得下面 4 个参数的方法请参考文章：[Discourse 使用 DiscourseConnect 来进行用户数据同步](https://www.isharkfly.com/t/discourse-discourseconnect/15776)

```auto
const apiKey = '4fe83002bb5fba8c9a61a65e5b4b0a3cf8233b0e4ccafc85ebd6607abab4651a';
const apiUser = 'system';
const connectSecret = 'jdhb19*Xh3!nu(#k';

```

### 设置 SSO 参数

参数的设置参考了 URL Get 方法的参数设置。

我们 Java 的代码为：

```auto
            URIBuilder builder = new URIBuilder();
            builder.addParameter("external_id", "1");
            builder.addParameter("email", "info@isharkfly.com");
            builder.addParameter("username", "info.visafn.sso");
            builder.addParameter("add_groups", "bar");
            builder.addParameter("require_activation", "false");
             url = StringUtils.removeStart(builder.build().toString(),"?");
            System.out.println(StringUtils.removeStart(url, "?"));

```

## Base64 和数字签名

当拿到上面 URL 的字符串后，我们有后面 2 个步骤要做。

第一个步骤就是对拿到的 URL 进行 Base64 转换，

第二个步骤就是对拿到已经转换成功的 Base64 字符串进行数字签名，签名这里用了 HMAC\_SHA\_256 算法。

同时在第一步获得密钥，需要作为参数结合算法参与运算。

```auto
        String sso= "admin/users/sync_sso";
        String sig= new HmacUtils(HmacAlgorithms.HMAC_SHA_256, "55619458534897").hmacHex(ssoPayload);

```

当拿到上面 2 个值后，重新构建一个 Json 数据结构。

类似下面的数据结构，然后作为 Post 参数的数据：

```auto
{
    "sso": "P2V4dGVybmFsX2lkPTEmZW1haWw9aW5mbyU0MHZpc2Fmbi5jb20mdXNlcm5hbWU9aW5mby52aXNhZm4mcmVxdWlyZV9hY3RpdmF0aW9uPXRydWU=",
    "sig": "403a205a004e37ffab2bf77cc12b2eac352d71820983706d86984eec9821a0c4"
}

```

## 发送 POST 请求

可以使用任何工具，只要支持 HTTP 的都可以。

现在 Java 用 OkHttp 比较多，所以我们就用 OkHttp 来发送请求。

```java
private OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(
                    MediaType.parse("application/json"), objectMapper.writeValueAsString(syncSSO));
            Response response = client.newCall(postRequest(path, body)).execute();

```

上面的 postRequest 是一个方法，在这个方法中我们利用已有的参数来构造请求。

方法是这样写的：

```java
    public Request postRequest(String path, RequestBody body) {
        HttpUrl.Builder urlBuilder = HttpUrl.parse(site_url + path).newBuilder();
        Request request = new Request.Builder().url(urlBuilder.build().toString())
                .addHeader("api-username", api_username)
                .addHeader("api-key", api_key)
                .post(body)
                .build();
        return request;
    }

```

如果没有问题，上面的代码就能完成 SSO 数据的同步调用。
