我正在尝试理解并实现我们的新REST服务器和现有客户端应用程序之间的客户端凭据流.我已经像这样设置了spring-security OAuth2 .根据我的理解,到目前为止,我的服务器现在应该支持以下请求:
$ curl -X -v -d 'client_id=the_client&client_secret=secret&grant_type=client_credentials' -X POST "http://localhost:9090/oauth/token"
Run Code Online (Sandbox Code Playgroud)
但我明白了
InsufficientAuthenticationException: There is no client authentication
Run Code Online (Sandbox Code Playgroud)
由引起的Principal是null这里(弹簧安全码):
@FrameworkEndpoint
@RequestMapping(value = "/oauth/token")
public class TokenEndpoint extends AbstractEndpoint {
@RequestMapping
public ResponseEntity<OAuth2AccessToken> getAccessToken(Principal principal,
@RequestParam("grant_type") String grantType, @RequestParam Map<String, String> parameters) {
if (!(principal instanceof Authentication)) {
throw new InsufficientAuthenticationException(
Run Code Online (Sandbox Code Playgroud)
所以看来,我需要先对服务器进行身份验证.但这不是我想要做的.我希望我的两台服务器使用共享密钥互相通信.OAuth提供程序服务器应根据请求向(受信任)客户端服务器提供访问令牌,以便客户端服务器可以使用该令牌访问服务器上的所有REST资源.这应该保护REST资源免受外部访问.
后来我想向第三方提供所选资源,并最终为服务器到服务器通信实现一些更细粒度的安全性.但是现在我需要保护REST服务器免受外部访问.
看起来我可能对整个客户端凭证流程或弹簧安全的应用有一些误解,因此任何澄清将非常感激.
我已经使用spring的sparklr示例应用程序和我在网上找到的几个示例实现了spring oauth2的资源所有者流程.我用curl测试了令牌请求部分,以便提供客户端和用户凭据:
curl -v --data "username=user1&password=user1&client_id=client1&client_secret=client1&grant_type=password" -X POST "http://localhost:8080/samplerestspringoauth2/oauth/token"
Run Code Online (Sandbox Code Playgroud)
它工作正常,但我做了以下观察:
虽然根据我看到的例子,我使用了BasicAuthentication过滤器,但这并没有真正用于安全过程.由于令牌请求不包含Authentication头,因此BasicAuthentication过滤器只会跳过任何检查.ClientCredentialsTokenEndpointFilter和authentication-server是唯一在令牌请求期间执行安全检查的人.注意到并通过调试验证后,我试图完全删除以下部分:
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
从配置.但后来我收到了警告:
"无法建立AuthenticationEntryPoint.请确保您具有通过命名空间配置的登录机制(例如表单登录)或指定具有'entry-point-ref'属性的自定义AuthenticationEntryPoint".
下一步,我在http命名空间中添加了entry-point-ref ="clientAuthenticationEntryPoint,并取消了警告.我测试了应用程序并正确播放.
但是,除了上述内容之外,我还在调试期间进行了以下观察:ClientCredentialsTokenEndpointFilter在私有变量中包含其自己的OAuth2AuthenticationEntryPoint入口点,并在由于错误的客户端凭据而失败时使用它.因此,无论在基本过滤器中还是在http命名空间中指定的入口点都无关紧要.最后,ClientCredentialsTokenEndpointFilter将使用自己的私有OAuth2AuthenticationEntryPoint.总结一下我的结论似乎如下:
下面我将令牌请求的http和端点配置供您参考.我跳过其余的配置以保持帖子易于阅读:
<http pattern="/oauth/token" create-session="stateless"
authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<custom-filter ref="clientCredentialsTokenEndpointFilter"
before="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="springsec/client" />
<property name="typeName" value="Basic" />
</bean>
Run Code Online (Sandbox Code Playgroud)
我还假设在令牌请求的原始sparklr应用程序(即spring oauth2示例应用程序)配置中也发生了同样的问题,这非常相似.可以在https://github.com/spring-projects/spring-security-oauth/blob/master/samples/oauth2/sparklr/src/main/webapp/WEB-INF/spring-servlet.xml中找到 ,相关部分如下:
<http pattern="/oauth/token" create-session="stateless"
authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/**" method="GET" access="ROLE_DENY" />
<intercept-url pattern="/**" method="PUT" access="ROLE_DENY" />
<intercept-url pattern="/**" method="DELETE" …Run Code Online (Sandbox Code Playgroud)