Spring 安全 Oauth2 - InsufficientAuthenticationException:需要身份验证才能获取访问令牌(不允许匿名)
Spring Security Oauth2 - InsufficientAuthenticationException: Authentication is required to obtain an access token (anonymous not allowed)
我正在尝试了解为什么客户端中的匿名用户无法获得访问令牌。
我发现这个 post on the Spring Blog 关于这个话题,Dave Syer 回答了这个:
Remember this is an issue to do with the client app, not the auth
server, so try and see it from the point of view of the cllient. At
step 1. there is a user trying to access a protected resource. If you
can't idenitify that user then all your users end up with the same
access token (the one that the first user obtains using his
credentials at the auth server). This is definitely a bad idea.
但是我不明白为什么匿名用户会共享相同的令牌:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth instanceof AnonymousAuthenticationToken) {
if (!resource.isClientOnly()) {
throw new InsufficientAuthenticationException(
"Authentication is required to obtain an access token (anonymous not allowed)");
}
}
虽然他们没有完全验证,但他们有一个 JSESSIONID 绑定到每个匿名用户。
包含 accessToken 的 OAuth2ClientContext
是一个会话范围的 Spring bean。由于匿名用户有一个 HttpSession,他们有独立的 OAuth2ClientContext
s,所以他们可以存储单独的 accessTokens。
有人可以解释一下这是否有意义或我不理解的地方吗?
我相信这并没有真正绑定到会话。 Dave 可能意味着您在 spring 上下文中只能有一个匿名用户。为什么这个 anonymous user
术语存在对我来说一直是个谜,但它的故事不同。
查看JdbcClientTokenServices
中方法getAccessToken
的代码 class
public OAuth2AccessToken getAccessToken(OAuth2ProtectedResourceDetails resource, Authentication authentication) {
OAuth2AccessToken accessToken = null;
try {
accessToken = jdbcTemplate.queryForObject(selectAccessTokenSql, new RowMapper<OAuth2AccessToken>() {
public OAuth2AccessToken mapRow(ResultSet rs, int rowNum) throws SQLException {
return SerializationUtils.deserialize(rs.getBytes(2));
}
}, keyGenerator.extractKey(resource, authentication));
}
catch (EmptyResultDataAccessException e) {
if (LOG.isInfoEnabled()) {
LOG.debug("Failed to find access token for authentication " + authentication);
}
}
return accessToken;
}
它在数据库中使用序列化身份验证。因此,即使在不同的会话中,它也会使用相同的匿名用户来加载令牌,从而有效地加载完全相同的令牌。
在 authorization_code
oauth2 流程中,您需要 code
来获取令牌(因此第一步是请求代码,只有在授权用户后才会提供代码 - 用户可能会被重定向到让我们说 facebook在此步骤中)。第二步是通过给出 code
来获取 token
。 code
在 db 中有限制授权,所以 spring 知道谁是新令牌的所有者:
\d+ oauth_code;
Table "mydb.oauth_code"
Column | Type | Modifiers | Storage | Stats target | Description
----------------+------------------------+--------------------------------- ------------------------+----------+--------------+-------------
id | integer | not null default nextval('oauth_code_id_seq'::regclass) | plain | |
authentication | bytea | | extended | |
code | character varying(255) | | extended | |
因此,总而言之,OAuth2ClientContext
的作用域为 session
或 request
,如果您要用相同的标记填充它,将无济于事。
我正在尝试了解为什么客户端中的匿名用户无法获得访问令牌。
我发现这个 post on the Spring Blog 关于这个话题,Dave Syer 回答了这个:
Remember this is an issue to do with the client app, not the auth server, so try and see it from the point of view of the cllient. At step 1. there is a user trying to access a protected resource. If you can't idenitify that user then all your users end up with the same access token (the one that the first user obtains using his credentials at the auth server). This is definitely a bad idea.
但是我不明白为什么匿名用户会共享相同的令牌:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth instanceof AnonymousAuthenticationToken) {
if (!resource.isClientOnly()) {
throw new InsufficientAuthenticationException(
"Authentication is required to obtain an access token (anonymous not allowed)");
}
}
虽然他们没有完全验证,但他们有一个 JSESSIONID 绑定到每个匿名用户。
包含 accessToken 的 OAuth2ClientContext
是一个会话范围的 Spring bean。由于匿名用户有一个 HttpSession,他们有独立的 OAuth2ClientContext
s,所以他们可以存储单独的 accessTokens。
有人可以解释一下这是否有意义或我不理解的地方吗?
我相信这并没有真正绑定到会话。 Dave 可能意味着您在 spring 上下文中只能有一个匿名用户。为什么这个 anonymous user
术语存在对我来说一直是个谜,但它的故事不同。
查看JdbcClientTokenServices
中方法getAccessToken
的代码 class
public OAuth2AccessToken getAccessToken(OAuth2ProtectedResourceDetails resource, Authentication authentication) {
OAuth2AccessToken accessToken = null;
try {
accessToken = jdbcTemplate.queryForObject(selectAccessTokenSql, new RowMapper<OAuth2AccessToken>() {
public OAuth2AccessToken mapRow(ResultSet rs, int rowNum) throws SQLException {
return SerializationUtils.deserialize(rs.getBytes(2));
}
}, keyGenerator.extractKey(resource, authentication));
}
catch (EmptyResultDataAccessException e) {
if (LOG.isInfoEnabled()) {
LOG.debug("Failed to find access token for authentication " + authentication);
}
}
return accessToken;
}
它在数据库中使用序列化身份验证。因此,即使在不同的会话中,它也会使用相同的匿名用户来加载令牌,从而有效地加载完全相同的令牌。
在 authorization_code
oauth2 流程中,您需要 code
来获取令牌(因此第一步是请求代码,只有在授权用户后才会提供代码 - 用户可能会被重定向到让我们说 facebook在此步骤中)。第二步是通过给出 code
来获取 token
。 code
在 db 中有限制授权,所以 spring 知道谁是新令牌的所有者:
\d+ oauth_code;
Table "mydb.oauth_code"
Column | Type | Modifiers | Storage | Stats target | Description
----------------+------------------------+--------------------------------- ------------------------+----------+--------------+-------------
id | integer | not null default nextval('oauth_code_id_seq'::regclass) | plain | |
authentication | bytea | | extended | |
code | character varying(255) | | extended | |
因此,总而言之,OAuth2ClientContext
的作用域为 session
或 request
,如果您要用相同的标记填充它,将无济于事。