繁体   English   中英

Spring oAuth2并发请求死锁

[英]Spring oAuth2 Concurrent Request Deadlock

我正在使用org.springframework.security.oauth2库和MySQL 5.5.58

在大多数情况下,它可以按预期工作,没有任何问题。 但是,似乎在完全相同的时间(分别在不同的服务器节点上)发生多个对“ / oauth / token”的请求时,服务器正在争用db记录,并且存在死锁:

Handling error: DeadlockLoserDataAccessException, PreparedStatementCallback; SQL [delete from oauth_access_token where token_id = ?]; Deadlock found when trying to get lock; try restarting transaction; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction

还有其他人看到过这个问题吗? 我如何避免这种行为?

谢谢

此并发问题导致生成2个具有相同token_id的oauth_access_token。 因此,稍后当JdbcTokenStore尝试通过其键(token_id)获取oauth_access_token或将其删除时,由于NonUniqueResultException或DeadlockLoserDataAccessException,该操作可能会失败。

我的解决方案是将oauth_access_token模式更新为对token_id具有唯一约束,以便首先避免不当重复。 请注意,这确实意味着第二个请求将失败(无论如何都是多余的),但是该用户至少有一个且只有一个令牌,并且数据将保持有效且不会损坏。

另外,我将JdbcTokenStore扩展为CustomTokenStore,从而扩展了错误处理和清除功能,以使数据库保持稳定状态。

@Override
public OAuth2Authentication readAuthentication(OAuth2AccessToken token) {
    try{
        return super.readAuthentication(token.getValue());
    }
    catch (RuntimeException e){
        OAuth2RefreshToken refreshToken = token.getRefreshToken();
        removeRefreshToken(refreshToken);
        removeAccessToken(token);
        logger().error("readAuthentication", e);
        throw e;
    }
}

@Override
public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
    logger().info("getAccessToken begin");
    try{
        return super.getAccessToken(authentication);
    }
    catch (IncorrectResultSizeDataAccessException e){
        logger().error("getAccessToken", e);
        safeRemoveAllAccessToken(authentication);
    }
    catch (RuntimeException e){
        logger().error("getAccessToken", e);
    }
    return null;
}

@Override
public OAuth2Authentication readAuthentication(String token) {
    try{
        OAuth2Authentication oAuth2Authentication = super.readAuthentication(token);

        if(oAuth2Authentication == null){
            removeAccessToken(token);
            removeRefreshToken(token);
        }
        return oAuth2Authentication;
    }
    catch (RuntimeException e){
        logger().error("readAuthentication", e);
        throw e;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM