6

我们正在使用资源所有者凭证授权类型(使用oauth2:passwordin security-config.xml。让我们播放这个场景来解释我的困境:

  1. Bob 是由当局创建的ROLE_USER
  2. Bob 尝试访问受 oauth2 保护的资源
  3. Bob 使用官方移动应用程序访问它,因此客户端凭据是正确的
  4. Bob 的访问令牌被创建并存储在 中TokenStore,键入他的usernameclient_idscope。(参见DefaultAuthenticationKeyGenerator.java
  5. Bob 的电话尝试使用此访问令牌调用受保护的服务,但这些服务要求用户authority拥有ROLE_MOBILE_USER.
  6. Bob 联系了数据库所有者,并ROLE_MOBLE_USER在数据库中添加了他的用户。
  7. Bob 尝试获取另一个访问令牌,但DefaultTokenServices返回给他的是相同的、无效的访问令牌。
  8. 利用他的新访问令牌的唯一方法authority是等到他的旧访问令牌过期,这样他就可以得到一个正确的新访问令牌authority

有很多方法可以解决这个问题。

一方面,添加ROLE_MOBILE_USER到 Bob 权限的管理应用程序可以清除数据库中的所有访问令牌和授权。这样,DefaultTokenServices将只创建一个具有正确权限的新权限,并将其序列化为他的新 OAuth2Authentication。但是,我们现在可能不希望 Administration webapp 关注 OAuth(至少现在还没有)。如果可能的话,我们希望管理应用程序的关注点尽可能简洁,并且现在不依赖于 oauth。

DELETE我们可以将该方法暴露给/oauth/access_token端点,并告诉移动应用程序尝试删除该访问令牌并重新请求一个,以防万一存储authorities过时。不过,这感觉更像是一种解决方法。

最后我可以authorities在我自己定义的AuthenticationKeyGenerator. 它基本上会使用授权的 、 、 和 ,并对它们执行相同的username摘要client_id算法scopeauthorities这样,当 Bob 尝试登录时,他将获得相同的访问令牌,但底层令牌存储将识别出他具有不同的身份验证(来自令牌授​​予者 bean 中的身份验证管理器)并刷新其数据库。我对这个解决方案的问题是它仅仅依赖于底层令牌存储的实现行为(尽管两者都InMemoryTokenStoreJdbcTokenStore这种方式运行)。

你能想到任何更好/更清洁的解决方案吗?这是我想太多了吗?

提前致谢。

4

3 回答 3

2

我在我的应用程序中解决了这个问题,方法是在发送身份验证信息时删除给定用户的所有令牌。

使用自定义 AuthenticationProvider bean。

@Component("authenticationProvider")
public class AuthenticationProviderImpl implements AuthenticationProvider

在令牌存储 bean 中自动装配。

@Autowired
@Qualifier("tokenStore")
private TokenStore tokenStore;

然后在身份验证方法中,如果第二次传递凭据,则删除给定用户的所有令牌。

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;

    try {
         //Do authentication

        //Delete previous tokens
        Collection<OAuth2AccessToken> tokenCollection = tokenStore.findTokensByUserName(token.getName());
        for (OAuth2AccessToken oToken : tokenCollection){
            tokenStore.removeAccessToken(oToken);
        }

        //return Authentication;
    }
}

大多数请求将使用令牌并完全绕过它,但是当凭据传递时,将生成一个新令牌。此令牌将与新的身份验证对象相关联,该对象将包括所有新角色以及对用户所做的更改。

于 2013-10-18T03:30:02.047 回答
1

我有同样的问题,我用这个函数解决了它:

protected void reloadUserFromSecurityContext(SecurityContext securityContext, Person user){
    OAuth2Authentication requestingUser = (OAuth2Authentication) securityContext.getUserPrincipal();
    Object principal = (PersonUserDetails) requestingUser.getUserAuthentication().getPrincipal();
    if(principal instanceof PersonUserDetails) {
        ((PersonUserDetails) principal).setPerson(user);
    }
    OAuth2AuthenticationDetails authDetails = (OAuth2AuthenticationDetails) requestingUser.getDetails();
    OAuth2AccessToken tokenStored = jdbcTokenStore.readAccessToken(authDetails.getTokenValue());
    jdbcTokenStore.storeAccessToken(tokenStored, requestingUser);
}

这是更新 OAuth2Authentication 中的 PersonUserDetails 对象的属性的示例

于 2017-03-29T09:56:12.390 回答
0

我有同样的问题,这就是解决方案

@RequestMapping(value = "/updateToken", method = RequestMethod.POST)
 void updateToken(@RequestBody tokenReq req) { 
            Collection<OAuth2AccessToken> tokenCollection = tokenStore.findTokensByClientIdAndUserName(req.idclient, req.username);
            for (OAuth2AccessToken AToken : tokenCollection){
                OAuth2Authentication Auth = tokenStore.readAuthentication(AToken);
                OAuth2AccessToken newToken = tokenServices.createAccessToken(Auth);
                tokenStore.removeAccessToken(AToken);
                tokenStore.storeAccessToken(newToken, Auth);
            }

 }
于 2020-06-01T12:07:40.883 回答