本文共 12130 字,大约阅读时间需要 40 分钟。
在 oauth2 的授权模式中有4种:
但如果我们想要增加一个自定义的授权模式,又该怎么做呢?
相关的源码是这样的:
public class CompositeTokenGranter implements TokenGranter { private final ListtokenGranters; public CompositeTokenGranter(List tokenGranters) { this.tokenGranters = new ArrayList (tokenGranters); } //四种授权模式+刷新令牌的模式根据grant_type判断 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); }}
oauth2 端点配置类部分源码:
public final class AuthorizationServerEndpointsConfigurer { // 省略部分代码 private TokenGranter tokenGranter; public AuthorizationServerEndpointsConfigurer tokenGranter(TokenGranter tokenGranter) { this.tokenGranter = tokenGranter; return this; } // 默认的四种授权模式+刷新令牌的模式的配置 private TokenGranter tokenGranter() { if (tokenGranter == null) { tokenGranter = new TokenGranter() { private CompositeTokenGranter delegate; @Override public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) { if (delegate == null) { delegate = new CompositeTokenGranter(getDefaultTokenGranters()); } return delegate.grant(grantType, tokenRequest); } }; } return tokenGranter; } // 默认的四种授权模式+刷新令牌的模式的配置 private ListgetDefaultTokenGranters() { ClientDetailsService clientDetails = clientDetailsService(); AuthorizationServerTokenServices tokenServices = tokenServices(); AuthorizationCodeServices authorizationCodeServices = authorizationCodeServices(); OAuth2RequestFactory requestFactory = requestFactory(); List 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 (authenticationManager != null) { // 添加密码模式 tokenGranters.add(new ResourceOwnerPasswordTokenGranter(authenticationManager, tokenServices, clientDetails, requestFactory)); } // 可以复制相关代码,然后这里添加自定义的授权模式 return tokenGranters; }}
看到这里就可以发现 spring 已经把默认的四种授权模式+刷新令牌的模式的配置在代码中写死了!
那又如何添加自定义的授权模式呢?
我的思路是这样的:
直接把这部分的代码复制,在其中添加自定义的授权模式。
我直接把密码模式复制,将其中的 GRANT_TYPE
的值改为 sms_code
,然后使用 /oauth/token?grant_type=sms_code&scope=read&username=user&password=123456
来验证结果。
/** * @author fengxuechao * @version 0.1 * @date 2019/5/17 */public class SmsCodeTokenGranter extends AbstractTokenGranter { // 仅仅复制了 ResourceOwnerPasswordTokenGranter,只是改变了 GRANT_TYPE 的值,来验证自定义授权模式的可行性 private static final String GRANT_TYPE = "sms_code"; private final AuthenticationManager authenticationManager; public SmsCodeTokenGranter( AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) { this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE); } protected SmsCodeTokenGranter( AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, String grantType) { super(tokenServices, clientDetailsService, requestFactory, grantType); this.authenticationManager = authenticationManager; } @Override protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) { Mapparameters = new LinkedHashMap (tokenRequest.getRequestParameters()); String username = parameters.get("username"); String password = parameters.get("password"); // Protect from downstream leaks of password parameters.remove("password"); Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password); ((AbstractAuthenticationToken) userAuth).setDetails(parameters); try { userAuth = authenticationManager.authenticate(userAuth); } catch (AccountStatusException ase) { //covers expired, locked, disabled cases (mentioned in section 5.2, draft 31) throw new InvalidGrantException(ase.getMessage()); } catch (BadCredentialsException e) { // If the username/password are wrong the spec says we should send 400/invalid grant throw new InvalidGrantException(e.getMessage()); } if (userAuth == null || !userAuth.isAuthenticated()) { throw new InvalidGrantException("Could not authenticate user: " + username); } OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest); return new OAuth2Authentication(storedOAuth2Request, userAuth); }}
/** * @author fengxuechao * @version 0.1 * @date 2019/5/17 */@Configuration@Profile("inMemory")public class TokenGranterConfig { @Autowired private ClientDetailsService clientDetailsService; @Autowired private UserDetailsService userDetailsService; @Autowired private AuthenticationManager authenticationManager; @Autowired private TokenStore tokenStore; @Autowired TokenEnhancer tokenEnhancer; private AuthorizationCodeServices authorizationCodeServices; private boolean reuseRefreshToken = true; private AuthorizationServerTokenServices tokenServices; private TokenGranter tokenGranter; /** * 授权模式 * * @return */ @Bean public TokenGranter tokenGranter() { if (tokenGranter == null) { tokenGranter = new TokenGranter() { private CompositeTokenGranter delegate; @Override public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) { if (delegate == null) { delegate = new CompositeTokenGranter(getDefaultTokenGranters()); } return delegate.grant(grantType, tokenRequest); } }; } return tokenGranter; } /** * 程序支持的授权类型 * * @return */ private ListgetDefaultTokenGranters() { AuthorizationServerTokenServices tokenServices = tokenServices(); AuthorizationCodeServices authorizationCodeServices = authorizationCodeServices(); OAuth2RequestFactory requestFactory = requestFactory(); List tokenGranters = new ArrayList (); // 添加授权码模式 tokenGranters.add(new AuthorizationCodeTokenGranter(tokenServices, authorizationCodeServices, clientDetailsService, requestFactory)); // 添加刷新令牌的模式 tokenGranters.add(new RefreshTokenGranter(tokenServices, clientDetailsService, requestFactory)); // 添加隐士授权模式 tokenGranters.add(new ImplicitTokenGranter(tokenServices, clientDetailsService, requestFactory)); // 添加客户端模式 tokenGranters.add(new ClientCredentialsTokenGranter(tokenServices, clientDetailsService, requestFactory)); if (authenticationManager != null) { // 添加密码模式 tokenGranters.add(new ResourceOwnerPasswordTokenGranter(authenticationManager, tokenServices, clientDetailsService, requestFactory)); // 添加自定义授权模式(实际是密码模式的复制) tokenGranters.add(new SmsCodeTokenGranter(authenticationManager, tokenServices, clientDetailsService, requestFactory)); } return tokenGranters; } /** * TokenServices * * @return */ private AuthorizationServerTokenServices tokenServices() { if (tokenServices != null) { return tokenServices; } this.tokenServices = createDefaultTokenServices(); return tokenServices; } /** * 授权码API * * @return */ private AuthorizationCodeServices authorizationCodeServices() { if (authorizationCodeServices == null) { authorizationCodeServices = new InMemoryAuthorizationCodeServices(); } return authorizationCodeServices; } /** * OAuth2RequestFactory的默认实现,它初始化参数映射中的字段, * 验证授权类型(grant_type)和范围(scope),并使用客户端的默认值填充范围(scope)(如果缺少这些值)。 * * @return */ private OAuth2RequestFactory requestFactory() { return new DefaultOAuth2RequestFactory(clientDetailsService); } /** * 默认 TokenService * * @return */ private DefaultTokenServices createDefaultTokenServices() { DefaultTokenServices tokenServices = new DefaultTokenServices(); tokenServices.setTokenStore(tokenStore); tokenServices.setSupportRefreshToken(true); tokenServices.setReuseRefreshToken(reuseRefreshToken); tokenServices.setClientDetailsService(clientDetailsService); tokenServices.setTokenEnhancer(tokenEnhancer); addUserDetailsService(tokenServices, this.userDetailsService); return tokenServices; } /** * 添加预身份验证 * * @param tokenServices * @param userDetailsService */ private void addUserDetailsService(DefaultTokenServices tokenServices, UserDetailsService userDetailsService) { if (userDetailsService != null) { PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider(); provider.setPreAuthenticatedUserDetailsService(new UserDetailsByNameServiceWrapper (userDetailsService)); tokenServices.setAuthenticationManager(new ProviderManager(Arrays. asList(provider))); } }}
package com.fengxuechao.examples.auth.config.inmemory;/** * @author fengxuechao * @version 0.1 * @date 2019/5/8 */@Slf4j@EnableAuthorizationServer@Configuration@Profile("inMemory")public class AuthorizationServerConfigInMemory extends AuthorizationServerConfigurerAdapter { // 省略部分代码 @Autowired private TokenGranter tokenGranter; /** * 认证服务器节点配置 * * @param endpoints * @throws Exception */ @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .tokenGranter(tokenGranter) // 四种授权模式+刷新令牌的模式+自定义授权模式 .tokenStore(tokenStore) .approvalStore(approvalStore) .userDetailsService(userDetailsService) .authenticationManager(authenticationManager) .setClientDetailsService(clientDetailsService); }}
POST http://localhost:8080/oauth/token?grant_type=sms_code&scope=read&username=user&password=123456HTTP/1.1 200 X-Application-Context: application:inMemoryCache-Control: no-storePragma: no-cacheX-Content-Type-Options: nosniffX-XSS-Protection: 1; mode=blockX-Frame-Options: DENYContent-Type: application/json;charset=UTF-8Transfer-Encoding: chunkedDate: Tue, 18 Jun 2019 07:13:12 GMT{ "access_token": "19f2e44a-6c9a-45c4-be7e-0aada6a0a9e6", "token_type": "bearer", "refresh_token": "f59336a8-03c4-4c85-bc31-16c6d80f1381", "expires_in": 359, "scope": "read", "organization": "userWqTI"}Response code: 200; Time: 335ms; Content length: 190 bytes
转载地址:http://htxzb.baihongyu.com/