SpringSecurity以及OAuth2源码分析——实现多登录方式

本文深入分析了SpringSecurity和OAuth2的源码,特别是OAuth2获取token的流程。详细讲解了如何实现多登录方式,包括自定义SpringSecurity过滤器、AuthenticationToken实现类、AuthenticationProvider,以及自定义TokenGranter整合OAuth2返回JWT的方式。通过自定义TokenGranter和Provider,可以灵活地扩展多种登录认证方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

版权声明:本文为博主ExcelMann的原创文章,未经博主允许不得转载。
作者:ExcelMann,转载需注明。

一、SpringSecurity以及OAuth2源码分析

我们先来看下通过OAuth2获取token的源码流程

一、获取token的接口是/oauth/token,在TokenEndpoint类中

public class TokenEndpoint extends AbstractEndpoint {
   
    @RequestMapping(value = "/oauth/token", method=RequestMethod.GET)
	public ResponseEntity<OAuth2AccessToken> getAccessToken(Principal principal, @RequestParam
	Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
   
		if (!allowedRequestMethods.contains(HttpMethod.GET)) {
   
			throw new HttpRequestMethodNotSupportedException("GET");
		}
		return postAccessToken(principal, parameters);
	}
	@RequestMapping(value = "/oauth/token", method=RequestMethod.POST)
	public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam
	Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
   
	    ...
	}
}

其中第一个接口是Get请求,第二个接口是Post请求,Get请求实质上最后也是调用Post请求的方法。

二、在postAccessToken方法中,其中最主要的代码是第132行

OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);

调用TokenEndpoint父类AbstractEndpoint的getTokenGranter()方法获取端点endpoint的tokenGranter,并调用granter的grant方法。

三、AuthorizationServerEndpointsConfigurer认证服务端点配置器

在上一句代码中,点击grant,可以发现该认证服务端点配置器。
这个认证服务端点配置器是我们在AuthorizationServerConfig认证服务配置器中,其中一个configure()重载方法,该方法的参数就是认证服务端点配置器(后续若新增自定义GrantType的话,需要在上述的认证服务配置器中的endpoint配置):

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
   ...}

而认证服务端点配置器中,有以下两个方法,是关于TokenGranter的初始化

private TokenGranter tokenGranter() {
   
    if (this.tokenGranter == null) {
   
        this.tokenGranter = new TokenGranter() {
   
            private CompositeTokenGranter delegate;

            public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
   
                if (this.delegate == null) {
   
                    this.delegate = new CompositeTokenGranter(AuthorizationServerEndpointsConfigurer.this.getDefaultTokenGranters());
                }

                return this.delegate.grant(grantType, tokenRequest);
            }
        };
    }

    return this.tokenGranter;
}
private List<TokenGranter> getDefaultTokenGranters() {
   
    ClientDetailsService clientDetails = this.clientDetailsService();
    AuthorizationServerTokenServices tokenServices = this.tokenServices();
    AuthorizationCodeServices authorizationCodeServices = this.authorizationCodeServices();
    OAuth2RequestFactory requestFactory = this.requestFactory();
    List<TokenGranter> tokenGranters = new ArrayList();
    tokenGranters.add(new AuthorizationCodeTokenGranter(tokenServices, authorizationCodeServices, clientDetails, requestFactory));
    tokenGranters.add(new RefreshTokenGranter(tokenServices, clientDetails, requestFactory));
    ImplicitTokenGranter implicit = new ImplicitTokenGranter(tokenServices, clientDetails, requestFactory);
    tokenGranters.add(implicit);
    tokenGranters.add(new ClientCredentialsTokenGranter(tokenServices, clientDetails, requestFactory));
    if (this.authenticationManager != null) {
   
        tokenGranters.add(new ResourceOwnerPasswordTokenGranter(this.authenticationManager, tokenServices, clientDetails, requestFactory));
    }

    return tokenGranters;
}

其中tokenGranter()方法创建了一个CompositeTokenGranter类对象,并调用getDefaultTokenGranters()方法,将默认的几种TokenGranter作为CompositeTokenGranter类对象的构造方法参数,添加到CompositeTokenGranter类的tokenGranters列表中。

四、CompositeTokenGranter

在这个TokenGranter中,由上述可知,存有默认的所有TokenGranter作为类的属性变量。

public class CompositeTokenGranter implements TokenGranter {
   

	private final List<TokenGranter> tokenGranters;
    
    public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
   
		for (TokenGranter granter : tokenGranters) {
   
			OAuth2AccessToken grant = granter.grant(grantType, tokenRequest);
			if (grant!=null) {
   
				return grant;
			}
		}
		return null;
	}
	
	public void addTokenGranter(TokenGranter tokenGranter) {
   
		if (tokenGranter == null) {
   
			throw new IllegalArgumentException("Token granter is null");
		}
		tokenGranters.add(tokenGranter);
	}

而其中grant()方法,具体就是遍历所有的granter,并调用当前granter的grant方法,得到的结果若不为空则返回。
其中的addTokenGranter()方法就是添加新的TokenGranter的方法。

五、AbstractTokenGranter

这个类是实现TokenGranter接口的一个抽象类,该类实现了TokenGranter接口的方法,并且其他的TokenGranter都是基于这个类来拓展(就可以不需要重新实现TokenGranter接口的大多数方法)。

比如:ClientCredentialsTokenGranter,就是在AbstractTokenGranter的基础上拓展的一个新的TokenGranter。

public class ClientCredentialsTokenGranter extends AbstractTokenGranter {
   

	private static final String GRANT_TYPE = "client_credentials";
    ...
    @Override
	public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
   
		OAuth2AccessToken token = super.grant(grantType, tokenRequest);
		if (token != null) {
   
			DefaultOAuth2AccessToken norefresh = new DefaultOAuth2AccessToken(token);
			// The spec says that client credentials should not be allowed to get a refresh token
			if (!allowRefresh) {
   
				norefresh.setRefreshToken(null);
			}
			token = norefresh;
		}
		return token;
	}
}

仔细分析grant方法可以发现,其实调用的还是父类(AbstractTokenGranter)的grant方法。
父类的grant方法如下:

public OAuth2AccessToken grant(String grantType
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值