SpringSecurity+OAUTH2集成多种登录方式

一、目前OAUTH2的提供了四种授权类型

Authorization Code(授权码模式):授权码模式, 通过授权码获取token进行资源访问。
Implicit(简化模式):用于移动应用程序或 Web 应用程序,这种模式比授权码模式少了code环节,回调url直接附带token。
Resource Owner Password Credentials(密码模式):资源所有者和客户端之间具有高度信任时(例如,客户端是设备的操作系统的一部分,或者是一个高度特权应用程序, 比如APP, 自研终端等),因为client可能存储用户密码。
Client Credentials(客户端模式):该模式直接根据client端的id和密钥即可获取token, 不需要用户参与, 适合内部的API应用服务使用。

但是在应用开发过程中,还存在多种登录方式,比如手机验证码、二维码扫码、微信登录等,如何在OAUTH2中集成其他多种登录方式。我们拿手机验证码登录模式举例,其他类型登录模式可以按照这种方式改造。

二、WEB端手机验证码登录

首先创建一个filter命名PhoneNumberAuthenticationFilter,该filter继承AbstractAuthenticationProcessingFilter类,oauth2自带的授权模式都是继承的该类,可以仿照password授权模式的过滤器UsernamePasswordAuthenticationFilter修改,修改请求地址为/phone/login,修改自己的参数。

public class PhoneNumberAuthenticationFilter extends
        AbstractAuthenticationProcessingFilter {

    public static final String SPRING_SECURITY_FORM_PHONE_KEY = "phone";
    public static final String SPRING_SECURITY_FORM_CODE_KEY = "code";

    private String phoneParameter = SPRING_SECURITY_FORM_PHONE_KEY;
    private String codeParameter = SPRING_SECURITY_FORM_CODE_KEY;
    private boolean postOnly = true;

    public PhoneNumberAuthenticationFilter() {
        super(new AntPathRequestMatcher("/phone/login", "POST"));
    }

    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {
        if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + request.getMethod());
        }

        String phone = obtainPhone(request);
        if (phone == null) {
            phone = "";
        }
        phone = phone.trim();

        String code = obtainCode(request);

        PhoneNumAuthenticationToken authRequest = new PhoneNumAuthenticationToken(
                phone, code);

        setDetails(request, authRequest);

        return this.getAuthenticationManager().authenticate(authRequest);
    }

    protected String obtainPhone(HttpServletRequest request) {
        return request.getParameter(phoneParameter);
    }

    protected String obtainCode(HttpServletRequest request) {
        return request.getParameter(codeParameter);
    }

    protected void setDetails(HttpServletRequest request,
                              PhoneNumAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }

}

创建自己的token类PhoneNumAuthenticationToken。

public class PhoneNumAuthenticationToken extends AbstractAuthenticationToken {

    private static final long serialVersionUID = 420L;
    private final Object phone;
    private Object code;

    public PhoneNumAuthenticationToken(Object phone, Object code) {
        super(null);
        this.phone = phone;
        this.code = code;
        this.setAuthenticated(false);
    }

    public PhoneNumAuthenticationToken(Object phone, Object code, Collection authorities) {
        super(authorities);
        this.phone = phone;
        this.code = code;
        super.setAuthenticated(true);
    }

    public Object getCredentials() {
        return this.code;
    }

    public Object getPrincipal() {
        return this.phone;
    }

    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        if (isAuthenticated) {
            throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        } else {
            super.setAuthenticated(false);
        }
    }

    public void eraseCredentials() {
        super.eraseCredentials();
        this.code = null;
    }
}

filter中要执行

this.getAuthenticationManager().authenticate(authRequest);

所以还要新增一个provider类PhoneAuthenticationProvider。

@Component
public class PhoneAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private IDaaSUserDetailsManager iDaaSUserDetailsManager;
    @Autowired
    private ValidateCodeRepository validateCodeRepository;

    /**
     * 手机号、验证码的认证逻辑
     * @param authentication 其实就是我们封装的 PhoneNumAuthenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        PhoneNumAuthenticationToken token = (PhoneNumAuthenticationToken) authentication;
        String phone = (String) authentication.getPrincipal();// 获取手机号
        String code = (String) authentication.getCredentials(); // 获取输入的验证码
        //从数据库获取验证码
        ValidateCode validateCode = validateCodeRepository.queryLastCodeByPhoneType(phone,"1");
        if(null == validateCode){
            throw new BadCredentialsException("不存在短信发送记录,请重新发送");
        }
        String phoneNum = validateCode.getCode();
        if (!phoneNum.equals(code)) {
            throw new PhoneNumBadCredentialsException("验证码不正确");
        }
        if(DateUtils.differenceSecond(new Date(),validateCode.getValidateTime())>0){
            throw new PhoneNumBadCredentialsException("该验证码已经失效,请重新发送,验证码有效期10分钟");
        }
        if(validateCode.getIfUse().equals("1")){
            throw new PhoneNumBadCredentialsException("该验证码已经使用,请重新发送");
        }
        // 2. 根据手机号查询用户信息
        UserDetails userDetails = (UserDetails) iDaaSUserDetailsManager.loadUserByUsername(phone);
        if (userDetails == null) {
            throw new PhoneNumBadCredentialsException("用户不存在,请联系管理员开通");
        }
        // 3. 把用户封装到 PhoneNumAuthenticationToken 中,
        // 后面就可以使用 SecurityContextHolder.getContext().getAuthentication(); 获取当前登陆用户信息
        PhoneNumAuthenticationToken authenticationResult = new PhoneNumAuthenticationToken(userDetails, code, userDetails.getAuthorities());
        authenticationResult.setDetails(token.getDetails());
        return authenticationResult;
    }


    /**
     * 判断是上面 authenticate 方法的 authentication 参数,是哪种类型
     * Authentication 是个接口,实现类有很多,目前我们最熟悉的就是 PhoneNumAuthenticationToken、UsernamePasswordAuthenticationToken
     * 很明显,我们只支持 PhoneNumAuthenticationToken,因为它封装的是手机号、验证码
     * @param authentication
     * @return
     */
    @Override
    public boolean supports(Class authentication) {
        // 如果参数是 PhoneNumAuthenticationToken 类型,返回true
        return (PhoneNumAuthenticationToken.class.isAssignableFrom(authentication));
    }
}

我们只需要做一个html页面,创建一个form请求,url为:/phone/login,参数用phone和code进行请求即可返回token。

三、移动端手机验证码登录

首先在oauth_client_details表authorized_grant_types增加新的授权方式,比如sms.

然后找到源码里面的AuthorizationServerEndpointsConfigurer类,在自己工程的相同目录下面创建相同类名的AuthorizationServerEndpointsConfigurer,并修改getDefaultTokenGranters方法下面添加自己的授权模式SmsTokenGranter。

public final class AuthorizationServerEndpointsConfigurer {

    private AuthorizationServerTokenServices tokenServices;

    private ConsumerTokenServices consumerTokenServices;

    private AuthorizationCodeServices authorizationCodeServices;

    private ResourceServerTokenServices resourceTokenServices;

    private TokenStore tokenStore;

    private TokenEnhancer tokenEnhancer;

    private AccessTokenConverter accessTokenConverter;

    private ApprovalStore approvalStore;

    private TokenGranter tokenGranter;

    private OAuth2RequestFactory requestFactory;

    private OAuth2RequestValidator requestValidator;

    private UserApprovalHandler userApprovalHandler;

    private AuthenticationManager authenticationManager;

    private ClientDetailsService clientDetailsService;

    private String prefix;

    private Map patternMap = new HashMap();

    private Set allowedTokenEndpointRequestMethods = new HashSet();

    private FrameworkEndpointHandlerMapping frameworkEndpointHandlerMapping;

    private boolean approvalStoreDisabled;

    private List interceptors = new ArrayList();

    private DefaultTokenServices defaultTokenServices;

    private UserDetailsService userDetailsService;

    private boolean tokenServicesOverride = false;

    private boolean userDetailsServiceOverride = false;

    private boolean reuseRefreshToken = true;

    private WebResponseExceptionTranslator exceptionTranslator;

    public AuthorizationServerTokenServices getTokenServices() {
        return ProxyCreator.getProxy(AuthorizationServerTokenServices.class,
                new ObjectFactory() {
                    @Override
                    public AuthorizationServerTokenServices getObject() throws BeansException {
                        return tokenServices();
                    }
                });
    }

    public TokenStore getTokenStore() {
        return tokenStore();
    }

    public TokenEnhancer getTokenEnhancer() {
        return tokenEnhancer;
    }

    public AccessTokenConverter getAccessTokenConverter() {
        return accessTokenConverter();
    }

    public ApprovalStore getApprovalStore() {
        return approvalStore;
    }

    public ClientDetailsService getClientDetailsService() {
        return ProxyCreator.getProxy(ClientDetailsService.class, new ObjectFactory() {
            @Override
            public ClientDetailsService getObject() throws BeansException {
                return clientDetailsService();
            }
        });
    }

    public OAuth2RequestFactory getOAuth2RequestFactory() {
        return ProxyCreator.getProxy(OAuth2RequestFactory.class, new ObjectFactory() {
            @Override
            public OAuth2RequestFactory getObject() throws BeansException {
                return requestFactory();
            }
        });
    }

    public OAuth2RequestValidator getOAuth2RequestValidator() {
        return requestValidator();
    }

    public UserApprovalHandler getUserApprovalHandler() {
        return userApprovalHandler();
    }

    public AuthorizationServerEndpointsConfigurer tokenStore(TokenStore tokenStore) {
        this.tokenStore = tokenStore;
        return this;
    }

    public AuthorizationServerEndpointsConfigurer tokenEnhancer(TokenEnhancer tokenEnhancer) {
        this.tokenEnhancer = tokenEnhancer;
        return this;
    }

    public AuthorizationServerEndpointsConfigurer reuseRefreshTokens(boolean reuseRefreshToken) {
        this.reuseRefreshToken = reuseRefreshToken;
        return this;
    }

    public AuthorizationServerEndpointsConfigurer accessTokenConverter(AccessTokenConverter accessTokenConverter) {
        this.accessTokenConverter = accessTokenConverter;
        return this;
    }

    public AuthorizationServerEndpointsConfigurer tokenServices(AuthorizationServerTokenServices tokenServices) {
        this.tokenServices = tokenServices;
        if (tokenServices != null) {
            this.tokenServicesOverride = true;
        }
        return this;
    }

    public boolean isTokenServicesOverride() {
        return tokenServicesOverride;
    }

    public boolean isUserDetailsServiceOverride() {
        return userDetailsServiceOverride;
    }

    public AuthorizationServerEndpointsConfigurer userApprovalHandler(UserApprovalHandler approvalHandler) {
        this.userApprovalHandler = approvalHandler;
        return this;
    }

    public AuthorizationServerEndpointsConfigurer approvalStore(ApprovalStore approvalStore) {
        if (approvalStoreDisabled) {
            throw new IllegalStateException("ApprovalStore was disabled");
        }
        this.approvalStore = approvalStore;
        return this;
    }

    /**
     * Explicitly disable the approval store, even if one would normally be added automatically (usually when JWT is not
     * used). Without an approval store the user can only be asked to approve or deny a grant without any more granular
     * decisions.
     *
     * @return this for fluent builder
     */
    public AuthorizationServerEndpointsConfigurer approvalStoreDisabled() {
        this.approvalStoreDisabled = true;
        return this;
    }

    public AuthorizationServerEndpointsConfigurer prefix(String prefix) {
        this.prefix = prefix;
        return this;
    }

    public AuthorizationServerEndpointsConfigurer pathMapping(String defaultPath, String customPath) {
        this.patternMap.put(defaultPath, customPath);
        return this;
    }

    public AuthorizationServerEndpointsConfigurer addInterceptor(HandlerInterceptor interceptor) {
        this.interceptors.add(interceptor);
        return this;
    }

    public AuthorizationServerEndpointsConfigurer addInterceptor(WebRequestInterceptor interceptor) {
        this.interceptors.add(interceptor);
        return this;
    }

    public AuthorizationServerEndpointsConfigurer exceptionTranslator(WebResponseExceptionTranslator exceptionTranslator) {
        this.exceptionTranslator = exceptionTranslator;
        return this;
    }

    /**
     * The AuthenticationManager for the password grant.
     *
     * @param authenticationManager an AuthenticationManager, fully initialized
     * @return this for a fluent style
     */
    public AuthorizationServerEndpointsConfigurer authenticationManager(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
        return this;
    }

    public AuthorizationServerEndpointsConfigurer tokenGranter(TokenGranter tokenGranter) {
        this.tokenGranter = tokenGranter;
        return this;
    }

    /**
     * N.B. this method is not part of the public API. To set up a custom ClientDetailsService please use
     * {@link AuthorizationServerConfigurerAdapter#configure(ClientDetailsServiceConfigurer)}.
     */
    public void setClientDetailsService(ClientDetailsService clientDetailsService) {
        this.clientDetailsService = clientDetailsService;
    }

    public AuthorizationServerEndpointsConfigurer requestFactory(OAuth2RequestFactory requestFactory) {
        this.requestFactory = requestFactory;
        return this;
    }

    public AuthorizationServerEndpointsConfigurer requestValidator(OAuth2RequestValidator requestValidator) {
        this.requestValidator = requestValidator;
        return this;
    }

    public AuthorizationServerEndpointsConfigurer authorizationCodeServices(
            AuthorizationCodeServices authorizationCodeServices) {
        this.authorizationCodeServices = authorizationCodeServices;
        return this;
    }

    public AuthorizationServerEndpointsConfigurer allowedTokenEndpointRequestMethods(HttpMethod... requestMethods) {
        Collections.addAll(allowedTokenEndpointRequestMethods, requestMethods);
        return this;
    }

    public AuthorizationServerEndpointsConfigurer userDetailsService(UserDetailsService userDetailsService) {
        if (userDetailsService != null) {
            this.userDetailsService = userDetailsService;
            this.userDetailsServiceOverride = true;
        }
        return this;
    }

    public ConsumerTokenServices getConsumerTokenServices() {
        return consumerTokenServices();
    }

    public ResourceServerTokenServices getResourceServerTokenServices() {
        return resourceTokenServices();
    }

    public AuthorizationCodeServices getAuthorizationCodeServices() {
        return authorizationCodeServices();
    }

    public Set getAllowedTokenEndpointRequestMethods() {
        return allowedTokenEndpointRequestMethods();
    }

    public OAuth2RequestValidator getRequestValidator() {
        return requestValidator();
    }

    public TokenGranter getTokenGranter() {
        return tokenGranter();
    }

    public FrameworkEndpointHandlerMapping getFrameworkEndpointHandlerMapping() {
        return frameworkEndpointHandlerMapping();
    }

    public WebResponseExceptionTranslator getExceptionTranslator() {
        return exceptionTranslator();
    }

    private ResourceServerTokenServices resourceTokenServices() {
        if (resourceTokenServices == null) {
            if (tokenServices instanceof ResourceServerTokenServices) {
                return (ResourceServerTokenServices) tokenServices;
            }
            resourceTokenServices = createDefaultTokenServices();
        }
        return resourceTokenServices;
    }

    private Set allowedTokenEndpointRequestMethods() {
        // HTTP POST should be the only allowed endpoint request method by default.
        if (allowedTokenEndpointRequestMethods.isEmpty()) {
            allowedTokenEndpointRequestMethods.add(HttpMethod.POST);
        }
        return allowedTokenEndpointRequestMethods;
    }

    private ConsumerTokenServices consumerTokenServices() {
        if (consumerTokenServices == null) {
            if (tokenServices instanceof ConsumerTokenServices) {
                return (ConsumerTokenServices) tokenServices;
            }
            consumerTokenServices = createDefaultTokenServices();
        }
        return consumerTokenServices;
    }

    private AuthorizationServerTokenServices tokenServices() {
        if (tokenServices != null) {
            return tokenServices;
        }
        this.tokenServices = createDefaultTokenServices();
        return tokenServices;
    }

    public AuthorizationServerTokenServices getDefaultAuthorizationServerTokenServices() {
        if (defaultTokenServices != null) {
            return defaultTokenServices;
        }
        this.defaultTokenServices = createDefaultTokenServices();
        return this.defaultTokenServices;
    }

    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;
    }

    private TokenEnhancer tokenEnhancer() {
        if (this.tokenEnhancer == null && accessTokenConverter() instanceof JwtAccessTokenConverter) {
            tokenEnhancer = (TokenEnhancer) accessTokenConverter;
        }
        return this.tokenEnhancer;
    }

    private AccessTokenConverter accessTokenConverter() {
        if (this.accessTokenConverter == null) {
            accessTokenConverter = new DefaultAccessTokenConverter();
        }
        return this.accessTokenConverter;
    }

    private TokenStore tokenStore() {
        if (tokenStore == null) {
            if (accessTokenConverter() instanceof JwtAccessTokenConverter) {
                this.tokenStore = new JwtTokenStore((JwtAccessTokenConverter) accessTokenConverter());
            }
            else {
                this.tokenStore = new InMemoryTokenStore();
            }
        }
        return this.tokenStore;
    }

    private ApprovalStore approvalStore() {
        if (approvalStore == null && tokenStore() != null && !isApprovalStoreDisabled()) {
            TokenApprovalStore tokenApprovalStore = new TokenApprovalStore();
            tokenApprovalStore.setTokenStore(tokenStore());
            this.approvalStore = tokenApprovalStore;
        }
        return this.approvalStore;
    }

    private boolean isApprovalStoreDisabled() {
        return approvalStoreDisabled || (tokenStore() instanceof JwtTokenStore);
    }

    private ClientDetailsService clientDetailsService() {
        if (clientDetailsService == null) {
            this.clientDetailsService = new InMemoryClientDetailsService();
        }
        if (this.defaultTokenServices != null) {
            addUserDetailsService(defaultTokenServices, userDetailsService);
        }
        return this.clientDetailsService;
    }

    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)));
        }
    }

    private UserApprovalHandler userApprovalHandler() {
        if (userApprovalHandler == null) {
            if (approvalStore() != null) {
                ApprovalStoreUserApprovalHandler handler = new ApprovalStoreUserApprovalHandler();
                handler.setApprovalStore(approvalStore());
                handler.setRequestFactory(requestFactory());
                handler.setClientDetailsService(clientDetailsService);
                this.userApprovalHandler = handler;
            }
            else if (tokenStore() != null) {
                TokenStoreUserApprovalHandler userApprovalHandler = new TokenStoreUserApprovalHandler();
                userApprovalHandler.setTokenStore(tokenStore());
                userApprovalHandler.setClientDetailsService(clientDetailsService());
                userApprovalHandler.setRequestFactory(requestFactory());
                this.userApprovalHandler = userApprovalHandler;
            }
            else {
                throw new IllegalStateException("Either a TokenStore or an ApprovalStore must be provided");
            }
        }
        return this.userApprovalHandler;
    }

    private AuthorizationCodeServices authorizationCodeServices() {
        if (authorizationCodeServices == null) {
            authorizationCodeServices = new InMemoryAuthorizationCodeServices();
        }
        return authorizationCodeServices;
    }

    private WebResponseExceptionTranslator exceptionTranslator() {
        if (exceptionTranslator != null) {
            return exceptionTranslator;
        }
        exceptionTranslator = new DefaultWebResponseExceptionTranslator();
        return exceptionTranslator;
    }

    private OAuth2RequestFactory requestFactory() {
        if (requestFactory != null) {
            return requestFactory;
        }
        requestFactory = new DefaultOAuth2RequestFactory(clientDetailsService());
        return requestFactory;
    }

    private OAuth2RequestValidator requestValidator() {
        if (requestValidator != null) {
            return requestValidator;
        }
        requestValidator = new DefaultOAuth2RequestValidator();
        return requestValidator;
    }

    private List getDefaultTokenGranters() {
        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 SmsTokenGranter(authenticationManager, tokenServices,
                    clientDetails, requestFactory));
            tokenGranters.add(new ResourceOwnerPasswordTokenGranter(authenticationManager, tokenServices,
                    clientDetails, requestFactory));
        }
        return tokenGranters;
    }

    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 FrameworkEndpointHandlerMapping frameworkEndpointHandlerMapping() {
        if (frameworkEndpointHandlerMapping == null) {
            frameworkEndpointHandlerMapping = new FrameworkEndpointHandlerMapping();
            frameworkEndpointHandlerMapping.setMappings(patternMap);
            frameworkEndpointHandlerMapping.setPrefix(prefix);
            frameworkEndpointHandlerMapping.setInterceptors(interceptors.toArray());
        }
        return frameworkEndpointHandlerMapping;
    }

}

创建手机验证码的granter类SmsTokenGranter

public class SmsTokenGranter extends AbstractTokenGranter {

    private static final String GRANT_TYPE = "sms";

    private final AuthenticationManager authenticationManager;

    public SmsTokenGranter(AuthenticationManager authenticationManager,
                                             AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
        this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
    }

    protected SmsTokenGranter(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) {

        Map parameters = new LinkedHashMap(tokenRequest.getRequestParameters());
//        validateCodeApplication.checkCode(parameters);
        String username = parameters.get("phone");
        String password = parameters.get("code");
        // Protect from downstream leaks of password
        parameters.remove("password");

        Authentication userAuth = new PhoneNumAuthenticationToken(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());
        }
        catch (PhoneNumBadCredentialsException e){
            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);
    }
}

在自己工程的AuthorizationServerConfigurerAdapter的实现类里面添加该granter

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsManager)
                .authorizationCodeServices(authorizationCodeServices)
                .tokenStore(tokenStore)
                .accessTokenConverter(jwtAccessTokenConverter)
                .reuseRefreshTokens(false);
        List granters = new ArrayList<>(Arrays.asList(endpoints.getTokenGranter()));
        /// 添加手机验证码的授权模式
        granters.add(new SmsTokenGranter(authenticationManager,endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory()));
        /// 这是一个组装模式,实现了TokenGranter接口,循环调用List中的TokenGranter组件进行校验处理,直到返回验证成功信息或者是异常信息
        CompositeTokenGranter compositeTokenGranter = new CompositeTokenGranter(granters);
        endpoints.tokenGranter(compositeTokenGranter);
    }

在调用/oauth/token接口获取token时,将grant_type改为sms,增加phone和code参数即可返回token.

你可能感兴趣的:(spring,oauth2,springsecurity,登录方式,token)