Spring Cloud OAuth2 自定義受權類型實現其餘方式登陸(短信驗證碼登陸、手機號密碼登陸)

實現效果

使用手機號密碼進行受權:
圖片描述
使用手機號短信驗證碼進行受權:
圖片描述
經過訪問令牌獲取當前用戶細節:
圖片描述git

添加依賴

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
    </dependencies>

建立用戶細節服務

@Service
public class CustomUserDetailsService {

    public UserDetails loadUserByPhoneAndPassword(String phone, String password) {
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(password)) {
            throw new InvalidGrantException("無效的手機號或短信驗證碼");
        }
        // 判斷成功後返回用戶細節
        return new User(phone, "", AuthorityUtils.commaSeparatedStringToAuthorityList("admin,user,root"));
    }

    public UserDetails loadUserByPhoneAndSmsCode(String phone, String smsCode) {
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(smsCode)) {
            throw new InvalidGrantException("無效的手機號或短信驗證碼");
        }
        // 判斷成功後返回用戶細節
        return new User(phone, "", AuthorityUtils.commaSeparatedStringToAuthorityList("admin,user,root"));
    }

}

建立自定義抽象令牌授予者

public abstract class AbstractCustomTokenGranter extends AbstractTokenGranter {

    protected AbstractCustomTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, String grantType) {
        super(tokenServices, clientDetailsService, requestFactory, grantType);
    }

    @Override
    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
        Map<String, String> parameters = new LinkedHashMap(tokenRequest.getRequestParameters());
        UserDetails details = getUserDetails(parameters);
        if (details == null) {
            throw new InvalidGrantException("沒法獲取用戶信息");
        }
        AuthenticationToken authentication = new AuthenticationToken(details.getAuthorities(),parameters, details);
        authentication.setAuthenticated(true);
        authentication.setDetails(details);
        OAuth2Request storedOAuth2Request = this.getRequestFactory().createOAuth2Request(client, tokenRequest);
        return new OAuth2Authentication(storedOAuth2Request, authentication);
    }

    protected abstract UserDetails getUserDetails(Map<String, String> parameters);
}

手機號密碼登陸令牌授予者

public class PhonePasswordCustomTokenGranter extends AbstractCustomTokenGranter {

    private CustomUserDetailsService userDetailsService;

    public PhonePasswordCustomTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, CustomUserDetailsService userDetailsService) {
        super(tokenServices, clientDetailsService, requestFactory,"custom_phone_pwd");
        this.userDetailsService = userDetailsService;
    }

    @Override
    protected UserDetails getUserDetails(Map<String, String> parameters) {
        String phone = parameters.get("phone");
        String password = parameters.get("password");
        parameters.remove("password");
        return userDetailsService.loadUserByPhoneAndPassword(phone, password);
    }
}

短信驗證碼登陸令牌授予者

public class PhoneSmsCustomTokenGranter extends AbstractCustomTokenGranter {

    private CustomUserDetailsService userDetailsService;

    public PhoneSmsCustomTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, CustomUserDetailsService userDetailsService) {
        super(tokenServices, clientDetailsService, requestFactory,"custom_phone_sms");
        this.userDetailsService = userDetailsService;
    }

    @Override
    protected UserDetails getUserDetails(Map<String, String> parameters) {
        String phone = parameters.get("phone");
        String smsCode = parameters.get("sms_code");
        return userDetailsService.loadUserByPhoneAndSmsCode(phone, smsCode);
    }
}

啓用受權服務器

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {

    @Autowired
    public CustomUserDetailsService customUserDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //定義一個客戶端支持自定義的受權類型
        clients.inMemory()
                .withClient("demo")
                .secret(passwordEncoder().encode("demo"))
                .authorizedGrantTypes("custom_phone_pwd","custom_phone_sms","refresh_token")
                .scopes("all");
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients()
                .tokenKeyAccess("isAuthenticated()")
                .checkTokenAccess("permitAll()");
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        List<TokenGranter> tokenGranters = getTokenGranters(endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory());
        tokenGranters.add(endpoints.getTokenGranter());
        endpoints.tokenGranter(new CompositeTokenGranter(tokenGranters));
    }

    private List<TokenGranter> getTokenGranters(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
        return new ArrayList<>(Arrays.asList(
                new PhoneSmsCustomTokenGranter(tokenServices, clientDetailsService, requestFactory, customUserDetailsService),
                new PhonePasswordCustomTokenGranter(tokenServices, clientDetailsService, requestFactory, customUserDetailsService)
        ));
    }
}

開啓資源認證

@Configuration
@EnableResourceServer
public class ResourceServerConfigurer extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .anyRequest()
                .authenticated();
    }
}

實現獲取用戶細節接口

@RestController
public class AuthController {
    @RequestMapping("/current-info")
    public Object getUser(Authentication authentication) {
        return authentication;
    }
}

項目源碼

https://gitee.com/yugu/demo-o...spring

總結

經過繼承AbstractCustomTokenGranter抽象令牌授予者類實現getUserDetails方法獲取須要的參數並調用CustomUserDetailsService用戶細節服務類的方法認證獲取用戶細節數據。服務器

相關文章
相關標籤/搜索