最近有一个使用 SSO 把已有的用户同步到 Discourse 的需求。 所以,我就根据官方针对 PHP 实现(Sync DiscourseConnect user data with the sync_sso route - developers - Discourse Meta )写了一个有关 Java 的实现。 实现的方法很简单,但是需要用到一些额外的包,最重要的是 Apache commons codec 和 Okhttp。 Apache commons codec 是用来生成数字签名的,Okhttp 是用来发送 Http Post 请求的。 设置相关的参数 这里有 4 个参数需要提前获得。 获得下面 4 个参数的方法请参考文章:Discourse 使用 DiscourseConnect 来进行用户数据同步 const apiKey = '4fe83002bb5fba8c9a61a65e5b4b0a3cf8233b0e4ccafc85ebd6607abab4651a'; const apiUser = 'system'; const connectSecret = 'jdhb19*Xh3!nu(#k'; 设置 SSO 参数 参数的设置参考了 URL Get 方法的参数设置。 我们 Java 的代码为: 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 算法。 同时在第一步获得密钥,需要作为参数结合算法参与运算。 String sso= "admin/users/sync_sso"; String sig= new HmacUtils(HmacAlgorithms.HMAC_SHA_256, "55619458534897").hmacHex(ssoPayload); 当拿到上面 2 个值后,重新构建一个 Json 数据结构。 类似下面的数据结构,然后作为 Post 参数的数据: { "sso": "P2V4dGVybmFsX2lkPTEmZW1haWw9aW5mbyU0MHZpc2Fmbi5jb20mdXNlcm5hbWU9aW5mby52aXNhZm4mcmVxdWlyZV9hY3RpdmF0aW9uPXRydWU=", "sig": "403a205a004e37ffab2bf77cc12b2eac352d71820983706d86984eec9821a0c4" } 发送 POST 请求 可以使用任何工具,只要支持 HTTP 的都可以。 现在 Java 用 OkHttp 比较多,所以我们就用 OkHttp 来发送请求。 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 是一个方法,在这个方法中我们利用已有的参数来构造请求。 方法是这样写的: 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 数据的同步调用。 https://www.isharkfly.com/t/sync-sso-discourseconnect-java/15790