1. 程式人生 > >Spring boot+Security OAuth2 爬坑日記(2)授權碼模式(升級篇)

Spring boot+Security OAuth2 爬坑日記(2)授權碼模式(升級篇)

1. 開發環境和本專案用到的框架

接著上一篇Spring boot+Security OAuth2 爬坑日記(1)授權碼模式部落格中的內容,上篇介紹了基本的開發環境,系統以及jdk版本等,本篇再來詳細介紹下專案中用到的框架和相關類庫。

框架/類庫/資料庫 版本號
java 11(Mac)/ 8(Win10)
spring-boot 2.0.5.RELEASE
spring-security 5.0.8.RELEASE
spring-security-oauth2 2.3.3.RELEASE
mybatis-plus 3.0.4
資料庫連線池(druid) 1.1.11
swagger-ui 2.9.2
hibernate-validator 6.0.13.Final
MySQL 5.7.22 MySQL Community Server
Redis 4.0.10

通過上述版本發現spring系列的版本都是最新的釋出版本,網上示例基本不多,使用必然會出現很多坑;當然有坑之後爬坑才能進步。可能有的人奇怪我為什麼用兩個版本,公司用肯定用java8,在自己的機器裡肯定用最新版來試水咯。。不說了老闆讓我修復趕緊修復bug,不然今天不能下班。。。。。。。。。。

上篇部落格中我們的客戶端資訊都是儲存在記憶體中的,本篇將客戶端資訊儲存於資料庫中;廢話不多說,開始擼碼!!!!!!!!

2. 專案結構

專案目錄結構

3. 自定義BootClientDetailsServiceBootClientDetails並配置

新建類 BootClientDetailsService

實現ClientDetailsService 介面,覆蓋loadClientByClientId(String clientId)方法,將其宣告為spring元件,方便後面配置使用

@Component
public final class BootClientDetailsService implements ClientDetailsService {

    @Autowired
    private IClientService clientService;

    @Override
    public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {

        Client client = this.clientService.findClientByClientId(clientId);

        if(client==null){
            throw new ClientRegistrationException("客戶端不存在");
        }

        return new BootClientDetails(client);
    }

}
@Data
public final class BootClientDetails implements ClientDetails {

    private Client client;

    public BootClientDetails(Client client) {
        this.client = client;
    }

    public BootClientDetails() {
    }

    @Override
    public String getClientId() {
        return client.getClientId();
    }

    @Override
    public Set<String> getResourceIds() {
        return client.getResourceIds()!=null?
                transformStringToSet(client.getResourceIds(),String.class):null;
    }

    @Override
    public boolean isSecretRequired() {
        return client.getIsSecretRequired();
    }

    @Override
    public String getClientSecret() {
        return client.getClientSecret();
    }

    @Override
    public boolean isScoped() {
        return client.getIsScoped();
    }

    @Override
    public Set<String> getScope() {
        return client.getScope()!=null?
                transformStringToSet(client.getScope(),String.class):null;
    }

    @Override
    public Set<String> getAuthorizedGrantTypes() {
        return client.getAuthorizedGrantTypes()!=null?
                transformStringToSet(client.getAuthorizedGrantTypes(),String.class):null;
    }

    @Override
    public Set<String> getRegisteredRedirectUri() {
        return client.getRegisteredRedirectUri()!=null?
                transformStringToSet(client.getRegisteredRedirectUri(),String.class):null;
    }

    @Override
    public Collection<GrantedAuthority> getAuthorities() {
        return (client.getAuthorities()!=null&&client.getAuthorities().trim().length()>0)?
                AuthorityUtils.commaSeparatedStringToAuthorityList(client.getAuthorities()):null;
    }

    @Override
    public Integer getAccessTokenValiditySeconds() {
        return client.getAccessTokenValiditySeconds();
    }

    @Override
    public Integer getRefreshTokenValiditySeconds() {
        return client.getRefreshTokenValiditySeconds();
    }

    @Override
    public boolean isAutoApprove(String scope) {
        return client.getIsAutoApprove();
    }

    @Override
    public Map<String, Object> getAdditionalInformation() {
        return null;
    }
}

將我們定義的 BootClientDetailsService配置在OAuth2AuthorizationServerConfig

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private BootClientDetailsService clientDetailsService;


    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        // 允許表單登入
       security.allowFormAuthenticationForClients();
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

       // String secret = passwordEncoder.encode("123qwe");

        clients.withClientDetails(clientDetailsService);
                /*// 客戶端儲存資訊儲存於記憶體中
                .inMemory()
                // 客戶端名稱
                .withClient("client")
                // 跳轉uri,可配置多個
                .redirectUris("http://localhost")
                // 許可權
               // .authorities("ROLE_USER")
                // 客戶端 secret
                .secret(secret)
                // 授權模式
                .authorizedGrantTypes("refresh_token","authorization_code");*/
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .tokenStore(new InMemoryTokenStore())
                .authenticationManager(authenticationManager);
    }
}

4. 建立註冊客戶端的介面ClientController


@RestController
@RequestMapping("client")
public class ClientController {

    @Autowired
    private IClientService clientService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @PostMapping("/register")
    public BaseResponse clientRegistered(@RequestBody @Valid Client client){

        client.setClientSecret(passwordEncoder.encode(client.getClientSecret()));

       int i= clientService.insert(client);
       return HttpResponse.baseResponse(200);
    }

}

完成客戶端註冊介面後,將客戶端註冊介面開放,不需要認證就能訪問

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.formLogin().and()
                .authorizeRequests()
                .antMatchers("/login","/oauth/*","/client/register")
                .permitAll()
                .antMatchers
                        ("/swagger-ui.html/**","/webjars/**",
                        "/swagger-resources/**","/v2/api-docs/**",
                        "/swagger-resources/configuration/ui/**","/swagger-resources/configuration/security/**",
                        "/images/**")
                .permitAll()
                .anyRequest()
                .authenticated()
                .and().csrf().disable();
    }

5. 測試

專案中已經整合好了swagger-ui,專案啟動後直接訪問http://localhost:8000/swagger-ui.html,出現如下頁面
註冊客戶端

通過swagger-ui註冊客戶端,請求引數如下

在這裡插入圖片描述

{
  "accessTokenValiditySeconds": 1800,
  "authorities": "ADMIN",
  "authorizedGrantTypes": "refresh_token,authorization_code",
  "clientId": "client1",
  "clientSecret": "123qwe",
  "isAutoApprove": false,
  "isSecretRequired": true,
  "refreshTokenValiditySeconds": 3600,
  "registeredRedirectUri": "http://localhost:7000",
  "scope": "all",
  "scoped": true,
  "secretRequired": true
}

客戶端註冊成功後就可以使用該客戶端的資訊申請授權,申請授權的步驟和Spring boot+Security OAuth2 爬坑日記(1)授權碼模式中的一樣,這裡不再贅述


原始碼地址 Github
微信公眾號:
在這裡插入圖片描述