OAuth2客戶端的配置參數(shù)非常多,雖然Id Server通過控制臺可視化解決了創(chuàng)建OAuth2客戶端的問題。但是如何進一步降低OAuth2的使用難度,把創(chuàng)建的OAuth2客戶端轉(zhuǎn)化為配置成為了剛需,從技術(shù)角度上感覺也并不是很難實現(xiàn)。
我們先來看看效果,點擊配置生成按鈕即可直接生成Spring Security的客戶端yaml配置:

這個效果是如何實現(xiàn)的呢?
highlightjs
主要依托于highlightjs這個代碼高亮庫,平常我們在各大技術(shù)社區(qū)看到的五顏六色的代碼塊很多就依賴的這個JS庫,連我自己的技術(shù)博客felord.cn都用了這個類庫來做代碼片段美化。它使用起來很簡單:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet"
>
<script src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</head>
<body>
<pre >
<code class="yaml">
spring:
#
application:
name: id-server
</code>
</pre>
</body>
</html>
引入一個風(fēng)格樣式和highlight.js庫,再加一個初始化腳本就完成了。然后在<pre><code>中編寫帶縮進的代碼就可以了,注意code標(biāo)簽要加上對應(yīng)語言或者腳本的class類,出來就是這樣的效果:

實現(xiàn)
到這里思路就很明確了,把參數(shù)項的值動態(tài)化就可以了,我期望達到這樣的效果:
<pre >
<code class="yaml">
spring:
#
application:
name: ${appName}
</code>
</pre>
但事實上我大意了,我用了thymeleaf模板,我沒有找到thymeleaf可以固化配置項到頁面的辦法,所以這個帶縮進的格式得后端生成,然后按照thymeleaf的要求渲染,于是我寫了一個非常復(fù)雜的方法:
@GetMapping("/system/client/yaml/{id}")
public String yaml(Model model, @PathVariable String id) {
OAuth2Client oauth2Client = clientRepository.findClientById(id);
String clientName = oauth2Client.getClientName();
String clientId = oauth2Client.getClientId();
Set<RedirectUri> redirectUris = oauth2Client.getRedirectUris();
String uris = redirectUris.stream()
.map(RedirectUri::getRedirectUri)
.collect(Collectors.joining(","));
Set<OAuth2GrantType> authorizationGrantTypes = oauth2Client.getAuthorizationGrantTypes();
String types = authorizationGrantTypes.stream()
.map(OAuth2GrantType::getGrantTypeName)
.collect(Collectors.joining(","));
String method = oauth2Client.getClientAuthenticationMethods().stream()
.map(ClientAuthMethod::getClientAuthenticationMethod)
.collect(Collectors.joining(","));
String scopes = Stream.concat(
oauth2Client.getScopes().stream()
.map(OAuth2Scope::getScope), Stream.of(OidcScopes.OPENID))
.collect(Collectors.joining(","));
LinkedHashMap<String, Object> client = new LinkedHashMap<>();
LinkedHashMap<String, Object> clientRegistration = new LinkedHashMap<>();
clientRegistration.put("client-id", clientId);
clientRegistration.put("client-secret", "請?zhí)顚懩愕腛Auth2客戶端密碼");
clientRegistration.put("redirect-uri", "請從" + uris + "指定一個");
clientRegistration.put("authorization-grant-type", "請從 " + types + " 指定一個");
clientRegistration.put("client-authentication-method", method);
clientRegistration.put("scope", scopes);
client.put("registration",
Collections.singletonMap(clientName, clientRegistration));
client.put("provider", Collections.singletonMap(clientName,
Collections.singletonMap("issuer-uri", "http://localhost:9000")));
Map<String, Object> spring =
Collections.singletonMap("spring",
Collections.singletonMap("security",
Collections.singletonMap("oauth2",
Collections.singletonMap("client", client))));
DumperOptions dumperOptions = new DumperOptions();
dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
Yaml yaml = new Yaml(dumperOptions);
String dump = yaml.dump(spring);
model.addAttribute("yaml", dump);
return "/system/client/yaml";
}
效果自然是有的,但是非常差強人意。

無法生成注釋,而且換行不受控制,尤其套了9個Map讓我抓狂。
優(yōu)化
是不是我把問題想得太復(fù)雜了呢?于是最終我把yaml的格式模板這樣做了:
String yml = "spring:\n" +
" security:\n" +
" oauth2:\n" +
" client:\n" +
" registration:\n" +
" # 這里為客戶端名稱可自行更改\n" +
" " + clientName + ":\n" +
" client-id: " + clientId + "\n" +
" # 密碼為注冊客戶端時的密碼\n" +
" client-secret: 請?zhí)顚懩洃浀腛Auth2客戶端密碼\n" +
" # 只能選擇一個\n" +
" redirect-uri: 請從" + uris + "指定一個\n" +
" # 只能選擇一個\n" +
" authorization-grant-type: " + types + "三選一\n" +
" client-authentication-method: " + method + "\n" +
" scope: " + scopes + "\n" +
" provider:\n" +
" " + clientName + ":\n" +
" # 要保證授權(quán)服務(wù)器地址可以被客戶端訪問\n" +
" issuer-uri: http://localhost:9000";
model.addAttribute("yaml", yml);
當(dāng)然這是為了兼容Java8,如果換了Java17直接就用字符串模板了,甚至這里我還能寫注釋,最終的效果是這樣的:

效果比上一個方案好了很多,當(dāng)然或許你還有更好的方案,讓我們集思廣益。
關(guān)于Id Server
倉庫地址:https://github.com/NotFound403/id-server 歡迎star。
Id Server是一個基于Spring Authorization Server的開源的授權(quán)服務(wù)器,大大降低OAuth2授權(quán)服務(wù)器的學(xué)習(xí)使用難度,提供UI控制臺,動態(tài)權(quán)限控制,方便OAuth2客戶端管理,可以一鍵生成Spring Security配置,開箱即用,少量配置修改就可部署,代碼開源,方便二次開發(fā),支持OAuth2四種客戶端認(rèn)證方式和三種授權(quán)模式。歡迎學(xué)習(xí)使用并參與代碼貢獻。
關(guān)注公眾號:碼農(nóng)小胖哥,獲取更多資訊