OAuth2AuthenticationManager源码跟踪

Posted agony-wxl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OAuth2AuthenticationManager源码跟踪相关的知识,希望对你有一定的参考价值。

本文仅助那些在Security集成OAuth2.0路上踩坑的人理解认证过程。

OAuth2AuthenticationManager

首先,我觉得分析OAuth2AuthenticationManager,我们需要先理解它是如何被使用,何时被使用,那我们就从这里开始逐一分析吧,我手画了一张图作为索引,以便我们理解,其中蓝色的为类,绿色的为接口,箭头指向的方向是实现类或者父类。
技术图片
因为里面接口和方法过多,所以不做展示,下面具体来进行代码分析。

 public class OAuth2AuthenticationManager implements AuthenticationManager, InitializingBean {

    private ResourceServerTokenServices tokenServices;

    private ClientDetailsService clientDetailsService;

    private String resourceId;

    public void setResourceId(String resourceId) {
        this.resourceId = resourceId;
    }

    public void setClientDetailsService(ClientDetailsService clientDetailsService) {
        this.clientDetailsService = clientDetailsService;
    }

    public void setTokenServices(ResourceServerTokenServices tokenServices) {
        this.tokenServices = tokenServices;
    }

    public void afterPropertiesSet() {
        Assert.state(tokenServices != null, "TokenServices are required");
    }

(3) public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        if (authentication == null) {
            throw new InvalidTokenException("Invalid token (token not found)");
        }
(3).1       String token = (String) authentication.getPrincipal();
(3).2       OAuth2Authentication auth = tokenServices.loadAuthentication(token);
        if (auth == null) {
            throw new InvalidTokenException("Invalid token: " + token);
        }

        Collection<String> resourceIds = auth.getOAuth2Request().getResourceIds();
        if (resourceId != null && resourceIds != null && !resourceIds.isEmpty() && !resourceIds.contains(resourceId)) {
            throw new OAuth2AccessDeniedException("Invalid token does not contain resource id (" + resourceId + ")");
        }

(3).3       checkClientDetails(auth);

        if (authentication.getDetails() instanceof OAuth2AuthenticationDetails) {
            OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
            // Guard against a cached copy of the same details
            if (!details.equals(auth.getDetails())) {
                // Preserve the authentication details from the one loaded by token services
                details.setDecodedDetails(auth.getDetails());
            }
        }
        auth.setDetails(authentication.getDetails());
(3).4       auth.setAuthenticated(true);
        return auth;

    }

    private void checkClientDetails(OAuth2Authentication auth) {
        if (clientDetailsService != null) {
            ClientDetails client;
            try {
                client = clientDetailsService.loadClientByClientId(auth.getOAuth2Request().getClientId());
            }
            catch (ClientRegistrationException e) {
                throw new OAuth2AccessDeniedException("Invalid token contains invalid client id");
            }
            Set<String> allowed = client.getScope();
            for (String scope : auth.getOAuth2Request().getScope()) {
                if (!allowed.contains(scope)) {
                    throw new OAuth2AccessDeniedException(
                            "Invalid token contains disallowed scope (" + scope + ") for this client");
                }
            }
        }
    }

}

OAuth2AuthenticationManager的成员变量

ResourceServerTokenServices

技术图片

以上是它的关系图,关于该接口,了解即可,不必过于深究,有兴趣的小伙伴们可以去翻看源码,学习一下代码结构也是不错的。
DefaultTokenServices 利用Security内置的令牌存储器(Tokenstore)接口进行数据库的CRUD操作,查看数据库结构及表说明

ClientDetailsService

技术图片
ClientDetailsService 用于加载客户端,有两种实现方式,一种是基于内存,一种是基于存储库的方式。

auth-server: http://localhost:18081/uac
server:
  port: 18082

security:
  oauth2:
    client:
      client-id: client1
      client-secret: 201314
      user-authorization-uri: ${auth-server}/oauth/authorize
      access-token-uri: ${auth-server}/oauth/token
    resource:
      jwt:
        key-uri: ${auth-server}/oauth/token_key
        key-value: 201314

上面是关于客户端的配置,auth-server 为资源服务器路径。

authenticate()

  • (3).1处的代码,期望传入的身份验证请求具有一个主体值,该主体值是一个访问令牌值(一般在(authorization header)请求头中)
  • (3).2处的代码,ResourceServerTokenServices通过查询数据库中 oauth_client_details该表,加载身份验证。
  • (3).3处的代码,检查资源id是否包含在授权请求中。
  • (3).4,通过身份认证,Security将OAuth2Authentication对象存入Session中,然后跳转到AuthorizationEndpointauthorize()。该方法跳出一个授权页面,提供授权的通过权或否决权。

以上就是我对于OAuth2AuthenticationManager源码的理解,仅供参考,如有不正确的地方,请提出指正。

以上是关于OAuth2AuthenticationManager源码跟踪的主要内容,如果未能解决你的问题,请参考以下文章