【发布时间】:2020-01-07 08:27:46
【问题描述】:
我在自定义身份验证处理程序的覆盖的 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 创建为 Map<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) 在 Map<String, Object> 的对象中返回带有虚拟映射的新 Principal
当我将 HashMap 添加到 Map<String, Object> 的 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 调用DefaultAuthenticationResultBuilder类的mergeAttributes函数,所以在我们在Principal 对象创建Map<String, Object>中发送的那个函数中,Principal 中的所有内容都作为List 返回。所以这意味着每个属性都作为列表返回?还下载了 CAS 源代码,看到他们的测试断言如 principal.getAttributes()[0] 暗示这是默认行为?我在任何地方都看不到任何文档,但没有任何意义。
4) 在 Map<String, Object> 的对象中返回带有 JSON 表示的新 Principal(几乎是一个解决方案)
我还尝试在属性的 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 没有使用它在我调用 /ticket URL 时使用的序列化程序。我尝试进行更多调试,但在 CAS 开始使用 cas-server-core-webflow-api
时卡在了某个地方我不想要这个:
{"rolesPerModule":["{\"TestModuleForBouncer_LIVE\":[\"ADMIN\"]}"]}
或者这个:
{"name":[ExampleName]} *(yes, no "" returned here)*
我想要喜欢:
{"rolesPerModule":{"{\"TestModuleForBouncer_LIVE\":[\"ADMIN\"]}"}}
或者这个
{"name":"ExampleName"}
【问题讨论】: