21
21
import java .util .Map ;
22
22
23
23
/**
24
+ * {@code DeviceClientAuthenticationConverter} 类实现了 {@link AuthenticationConverter} 接口,
25
+ * 用于将设备授权请求或设备访问令牌请求转换为 {@link DeviceClientAuthenticationToken} 实例。
26
+ *
27
+ * <p>它主要处理以下两类请求:</p>
28
+ * <ul>
29
+ * <li>设备授权请求(包含 "device_code" 参数)。</li>
30
+ * <li>设备访问令牌请求(包含 "grant_type=device_code" 和 "device_code" 参数)。</li>
31
+ * </ul>
32
+ *
33
+ * <p>该转换器对请求参数进行严格验证,如校验 client_id 是否唯一且有效。</p>
34
+ *
24
35
* @author: ReLive27
25
36
* @date: 2024/1/23 22:43
26
37
*/
27
38
public class DeviceClientAuthenticationConverter implements AuthenticationConverter {
39
+
40
+ /**
41
+ * 匹配设备授权请求的条件。
42
+ */
28
43
private final RequestMatcher deviceAuthorizationRequestMatcher ;
44
+
45
+ /**
46
+ * 匹配设备访问令牌请求的条件。
47
+ */
29
48
private final RequestMatcher deviceAccessTokenRequestMatcher ;
30
49
50
+ /**
51
+ * 构造函数,初始化请求匹配器。
52
+ *
53
+ * @param deviceAuthorizationEndpointUri 设备授权端点的 URI,用于匹配设备授权请求。
54
+ */
31
55
public DeviceClientAuthenticationConverter (String deviceAuthorizationEndpointUri ) {
56
+ // 匹配设备授权请求:路径匹配、响应类型为 device_code 且包含 client_id 参数
32
57
this .deviceAuthorizationRequestMatcher = new AndRequestMatcher (
33
58
new AntPathRequestMatcher (
34
59
deviceAuthorizationEndpointUri , HttpMethod .POST .name ()),
35
60
request -> "device_code" .equals (request .getParameter (OAuth2ParameterNames .RESPONSE_TYPE )),
36
61
request -> request .getParameter (OAuth2ParameterNames .CLIENT_ID ) != null );
62
+
63
+ // 匹配设备访问令牌请求:grant_type 为 device_code,且包含 device_code 和 client_id 参数
37
64
this .deviceAccessTokenRequestMatcher = request ->
38
65
AuthorizationGrantType .DEVICE_CODE .getValue ().equals (request .getParameter (OAuth2ParameterNames .GRANT_TYPE )) &&
39
66
request .getParameter (OAuth2ParameterNames .DEVICE_CODE ) != null &&
40
67
request .getParameter (OAuth2ParameterNames .CLIENT_ID ) != null ;
41
68
}
42
69
70
+ /**
71
+ * 转换请求为 {@link DeviceClientAuthenticationToken}。
72
+ *
73
+ * @param request 当前的 HTTP 请求。
74
+ * @return 如果请求匹配设备授权或设备访问令牌请求,返回一个 {@link DeviceClientAuthenticationToken},否则返回 {@code null}。
75
+ * @throws OAuth2AuthenticationException 如果请求参数无效(如缺少或多于一个 client_id)。
76
+ */
43
77
@ Nullable
44
78
@ Override
45
79
public Authentication convert (HttpServletRequest request ) {
80
+ // 请求不匹配设备授权请求或设备访问令牌请求,返回 null
46
81
if (!this .deviceAuthorizationRequestMatcher .matches (request ) &&
47
82
!this .deviceAccessTokenRequestMatcher .matches (request )) {
48
83
return null ;
49
84
}
50
85
51
- // client_id (REQUIRED)
86
+ // 提取 client_id,确保非空且唯一
52
87
String clientId = request .getParameter (OAuth2ParameterNames .CLIENT_ID );
53
88
if (!StringUtils .hasText (clientId ) ||
54
89
request .getParameterValues (OAuth2ParameterNames .CLIENT_ID ).length != 1 ) {
55
90
throw new OAuth2AuthenticationException (OAuth2ErrorCodes .INVALID_REQUEST );
56
91
}
92
+
93
+ // 提取额外的请求参数,排除 client_id 参数
57
94
Map <String , Object > additionalParameters = getParametersIfMatchesDeviceCodeGrantRequest (request ,
58
95
OAuth2ParameterNames .CLIENT_ID );
96
+
97
+ // 返回一个新的 DeviceClientAuthenticationToken 实例
59
98
return new DeviceClientAuthenticationToken (clientId , ClientAuthenticationMethod .NONE , null , additionalParameters );
60
99
}
61
100
101
+ /**
102
+ * 提取请求中的参数,排除指定的参数名(如 client_id)。
103
+ *
104
+ * @param request 当前的 HTTP 请求。
105
+ * @param exclusions 要排除的参数名。
106
+ * @return 返回一个包含请求参数的 Map,排除了指定的参数。
107
+ */
62
108
static Map <String , Object > getParametersIfMatchesDeviceCodeGrantRequest (HttpServletRequest request , String ... exclusions ) {
63
109
MultiValueMap <String , String > multiValueParameters = getParameters (request );
110
+
111
+ // 排除指定的参数
64
112
for (String exclusion : exclusions ) {
65
113
multiValueParameters .remove (exclusion );
66
114
}
@@ -72,17 +120,24 @@ static Map<String, Object> getParametersIfMatchesDeviceCodeGrantRequest(HttpServ
72
120
return parameters ;
73
121
}
74
122
123
+ /**
124
+ * 提取请求中的所有参数,并返回为 {@link MultiValueMap}。
125
+ *
126
+ * @param request 当前的 HTTP 请求。
127
+ * @return 包含请求参数的 {@link MultiValueMap}。
128
+ */
75
129
static MultiValueMap <String , String > getParameters (HttpServletRequest request ) {
76
130
Map <String , String []> parameterMap = request .getParameterMap ();
77
131
MultiValueMap <String , String > parameters = new LinkedMultiValueMap <>(parameterMap .size ());
132
+
78
133
parameterMap .forEach ((key , values ) -> {
79
134
if (values .length > 0 ) {
80
135
for (String value : values ) {
81
136
parameters .add (key , value );
82
137
}
83
138
}
84
139
});
140
+
85
141
return parameters ;
86
142
}
87
143
}
88
-
0 commit comments