spring security oauth2 的四种获取toke
authorizationCode授权码模式
https://www.cnblogs.com/hellxz/p/oauth2_oauthcode_pattern.html
password密码模式
https://www.cnblogs.com/hellxz/p/12041495.html
这里需要注意的是,认证端的endpoint必须配置authenticationManager,因为在源码里,不配置compositeGranter是没有password这种grantType的,导致会报错unsupport_grant_type的异常的。
认证配置类需要配置:
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);//密码模式必须添加authenticationManager
}
AuthorizationServerEndpointsConfigurer类:
private List<TokenGranter> getDefaultTokenGranters() {
ClientDetailsService clientDetails = clientDetailsService();
AuthorizationServerTokenServices tokenServices = tokenServices();
AuthorizationCodeServices authorizationCodeServices = authorizationCodeServices();
OAuth2RequestFactory requestFactory = requestFactory();
List<TokenGranter> tokenGranters = new ArrayList<TokenGranter>();
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 (authenticationManager != null) {
tokenGranters.add(new ResourceOwnerPasswordTokenGranter(authenticationManager, tokenServices,
clientDetails, requestFactory));
}
return tokenGranters;
}
ClientCredentials凭证模式(客户端模式)
https://www.cnblogs.com/hellxz/p/12041588.html
这里需要注意,返回的token格式,虽然定义了 自定义格式的token(继承DefaultOAuth2AccessToken并为其定义序列化器,使得返回带上msg和code这种统一json格式)
在获取token的过程,我们会经过这一代码
TokenEndpoint类
OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
grant方法是AbstractTokenGranter中执行的,其中继承AbstractTokenGranter的有五种,分别是:
-
ResourceOwnerPasswordTokenGranter
-
RefreshTokenGranter
-
ClientCredentialsTokenGranter
-
ImplicitTokenGranter
-
AuthorizationCodeTokenGranter
其中 ClientCredentialsTokenGranter 是有自己的grant()方法,其余四种是没有的,这就使得我们拿到DefaultOAuth2AccessToken之后再在自定义的TokenEnhancer中转化成自定义格式的OAuth2AccessToken,会原封不动的按照序列化器返回出去,而ClientCredentialsTokenGranter 的grant方法,如下:
@Override
public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
OAuth2AccessToken token = super.grant(grantType, tokenRequest); //这里拿到的还是自定义的OAuth2AccessToken
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;
}
第一句代码其实返回就是自定义的OAuth2AccessToken,之后在下面的判断中,就变为DefaultOAuth2AccessToken ,所以返回就是DefaultOAuth2AccessToken ,没有code、msg的统一json格式的token。而且它是没有refresh_token。
代码部分
这时我们可以自定义ClientCredentialsTokenGranter ,并且配置上就可以了:
首先就是模拟ClientCredentialsTokenGranter ,构建出自定义的ClientCredentialsTokenGranter :注意返回的是MyOauth2AccessToken
public class CustomClientCredentialsTokenGranter extends AbstractTokenGranter {
private static final String GRANT_TYPE = "client_credentials";
private boolean allowRefresh = false;
public CustomClientCredentialsTokenGranter(AuthorizationServerTokenServices tokenServices,
ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
this(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
}
protected CustomClientCredentialsTokenGranter(AuthorizationServerTokenServices tokenServices,
ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, String grantType) {
super(tokenServices, clientDetailsService, requestFactory, grantType);
}
public void setAllowRefresh(boolean allowRefresh) {
this.allowRefresh = allowRefresh;
}
@Override
public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
OAuth2AccessToken token = super.grant(grantType, tokenRequest);
if (token != null) {
//注意类型,这个自定义的token是含有自定义的序列化器,有msg和code返回的
MyOauth2AccessToken norefresh = new MyOauth2AccessToken(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;
}
}
然后在认证服务器配置类中:
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//MUST:密码模式下需设置一个AuthenticationManager对象,获取 UserDetails信息
//末确认点.userDetailsService(userDetailsService)
/*
使用 /pig4cloud/login 覆盖 原有的/oauth/token,注意这里是覆盖一旦配置 原有路径将失效
endpoints.pathMapping("/oauth/token","/pig4cloud/login");
*/
endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
endpoints.approvalStore(jdbcApprovalStore());
//tokenServices没有的话会自动创建一个默认的
endpoints.tokenServices(customTokenService());
//密码password模式必须加上
endpoints.authenticationManager(authenticationManager);
DefaultOAuth2RequestFactory factory = new DefaultOAuth2RequestFactory(jdbcClientDetailsService());
CustomClientCredentialsTokenGranter granter = new CustomClientCredentialsTokenGranter(
customTokenService(),jdbcClientDetailsService(),factory);
granter.setAllowRefresh(true);
endpoints.tokenGranter(granter);
}
这时返回就是统一的json格式,以及返回有refresh_token
{
"msg": "Success",
"code": 1000,
"data": {
"access_token": "3d1f89d4-e410-4559-b50b-6afa4b63fe5f",
"refresh_token": "8f68f072-8bc7-4f18-be97-16ae20e44926",
"scope": "user_info",
"customInfo": "extra thing额外的东西",
"token_type": "bearer",
"expires_in": 6943
}
}
implicit隐秘模式
https://www.cnblogs.com/hellxz/p/oauth2_impilit_pattern.html