我在自定义身份验证处理程序的覆盖的 authenticateUsernamePasswordInternal 函数中返回自定义属性时遇到 JSON 问题:
return createHandlerResult( credential,
this.getPrincipalFactory( ).createPrincipal( credential.getId( ), attributes) );
createPrincipal 方法接受哪个Map<String, Object>
Principal createPrincipal(String id, Map<String, Object> attributes);
当我Map<String, List>
输入属性时,CAS 返回列表的 toString 表示而不是它的 JSON 表示。简而言之,如何从这个函数返回正确的 JSON 属性序列化?
笔记:
- 使用的 CAS 版本:5.3.8
- 通过 AbstractUsernamePasswordAuthenticationHandler 扩展的自定义身份验证
- JWT 使用 CAS 协议实现
这是我到目前为止所尝试的:
1)CAS在验证服务时将List of HashMap转换为String(可能是根本原因)
当我创建 Principal asMap<String, new ArrayList<new HashMap<>>
时,我的 HashMap 被转换为 HashMap 的 toString 表示。所以它的类型信息现在从 HashMap -> String 转换,这使得 CAS 向我的客户端返回不正确的 JSON,因为 String 像 JSON 一样被序列化。它发生的地方->
AbstractUrlBasedTicketValidator -> validate() -> final String serverResponse = retrieveResponseFromServer(new URL(validationUrl), ticket);
这里 serverResponse 包含:
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
<cas:authenticationSuccess>
<cas:user>test</cas:user>
<cas:attributes>
<cas:roles>(Test,[ADMIN])</cas:roles>
</cas:attributes>
</cas:authenticationSuccess>
</cas:serviceResponse>
我的期望:
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
<cas:authenticationSuccess>
<cas:user>test</cas:user>
<cas:attributes>
<cas:roles>
<cas:Test>ADMIN</cas:Test>
</cas:roles>
</cas:attributes>
</cas:authenticationSuccess>
</cas:serviceResponse>
2) 在 Object 中返回带有虚拟 Map 的新 PrincipalMap<String, Object>
当我将 HashMap 添加到 的 Object 部分时,它会像mapMap<String, Object>
一样返回给客户端{"left": "key", "right": "value"}
。["key":"value"]
调试了这么久,看到CAS在请求/tickets URL时是如何使用json-smart-2.3库的。我看到当我在 Map 的 Object 中为属性发送 Map 时,json-smart 库使用它的 BeansWriter 序列化 Map,它获取类的字段并用作键。所以我发送 HashMap -> CAS 将其转换为 Java Pair(在下一步中描述) -> Pair 具有属性“left”和“right”,因此它将左右字段添加到我不想要的 JSON 正文中。
3) 调试 CAS 以了解它如何将属性序列化为 JSON 以进行 API 调用(令牌 url)
- 我寻找 CAS 以了解它如何处理 Principal,它将所有内容合并为 Pair 的 LinkedList。因此,出于这个原因,无论我在 Map 对象部分添加什么,它都会以 JSON 表示形式的数组形式返回,如 []。这意味着当我添加时
attributes.put("name", "ExampleName")
,它返回为"{"name":["ExampleName"]}
因为 CAS 调用类的mergeAttributes
函数,DefaultAuthenticationResultBuilder
所以 Principal 中的所有内容都作为我们在 Principal object creations 中发送的那个函数中的 List 返回Map<String, Object>
。所以这意味着每个属性都作为列表返回?还下载了 CAS 源代码,看到他们的测试断言如 principal.getAttributes()[0] 暗示这是默认行为?我在任何地方都看不到任何文档,但没有任何意义。
4)在对象中返回带有JSON表示的新主体Map<String, Object>
(几乎是一个解决方案)
我还尝试在属性的 Object 部分中直接返回 JSON 表示:
Map<String, Object> attributes = new HashMap<>();
String roles = "{"TestModule":["Name1"]}"; (didn't add escape quotes for simplicity)
attributes.put("roles", roles);
它按预期返回 JSON 用于对/ticket URL 的 API 调用,因为序列化库尝试序列化我发送的 String 所以这是一种令人困惑的解决方案,但仍然存在一些问题。如果我通过/login页面登录,CAS 会再次用 [] 包装每个属性。当我调试时,我看到这次 CAS 没有使用它在我 cal /ticket URL 时使用的序列化程序。我尝试进行更多调试,但在 CAS 开始使用cas-server-core-webflow-api时卡在某个地方
我不想要这个:
{"rolesPerModule":["{\"TestModuleForBouncer_LIVE\":[\"ADMIN\"]}"]}
或这个:
{"name":[ExampleName]} *(yes, no "" returned here)*
我想喜欢:
{"rolesPerModule":{"{\"TestModuleForBouncer_LIVE\":[\"ADMIN\"]}"}}
或这个
{"name":"ExampleName"}