pismile

Intégrer pismile avec Spring Boot

Connexion OIDC avec Spring Security, comptes locaux liés au sub, déconnexion complète.

2 min de lecture · Mis à jour le · API v1

Connectez-vous pour voir vos propres identifiants sandbox dans les exemples.

Ce guide construit une application Spring Boot 3 où les utilisateurs se connectent avec pismile. À la première connexion, un compte local est créé et lié au sub de l'utilisateur. Durée : 15 minutes.

  1. Ajoutez les dépendances

    pom.xml
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <scope>runtime</scope>
    </dependency>
  2. Déclarez pismile

    application.properties
    server.port=8090
    
    spring.security.oauth2.client.registration.pismile.client-id=VOTRE_CLIENT_ID
    spring.security.oauth2.client.registration.pismile.client-secret=${PISMILE_CLIENT_SECRET}
    spring.security.oauth2.client.registration.pismile.client-name=pismile
    spring.security.oauth2.client.registration.pismile.client-authentication-method=client_secret_basic
    spring.security.oauth2.client.registration.pismile.authorization-grant-type=authorization_code
    spring.security.oauth2.client.registration.pismile.scope=openid,profile
    spring.security.oauth2.client.registration.pismile.redirect-uri={baseUrl}/login/oauth2/code/{registrationId}
    spring.security.oauth2.client.provider.pismile.issuer-uri=https://pismile.com

    Au démarrage, Spring lit https://pismile.com/.well-known/openid-configuration et trouve seul les endpoints et les clés de signature.

  3. Créez le compte local

    Le sub est la clé du compte : jamais le nom.

    Account.java
    @Entity
    @Table(name = "accounts")
    public class Account {
    
        @Id
        @GeneratedValue(strategy = GenerationType.UUID)
        private UUID id;
    
        @Column(name = "pismile_sub", nullable = false, unique = true)
        private String pismileSub;
    
        @Column(name = "verified_name")
        private String verifiedName;
    
        @Column(name = "country", length = 2)
        private String country;
    
        @Column(name = "category", length = 1)
        private String category;
    
        @Column(name = "last_login_at")
        private Instant lastLoginAt;
    
        protected Account() {
        }
    
        public Account(String pismileSub) {
            this.pismileSub = pismileSub;
        }
    
        public void refresh(String name, String country, String category) {
            this.verifiedName = name;
            this.country = country;
            this.category = category;
            this.lastLoginAt = Instant.now();
        }
    
        public String getVerifiedName() { return verifiedName; }
        public String getCountry() { return country; }
        public String getCategory() { return category; }
    }
    AccountRepository.java
    public interface AccountRepository extends JpaRepository<Account, UUID> {
        Optional<Account> findByPismileSub(String pismileSub);
    }
  4. Liez chaque connexion au compte

    Ce service est appelé à chaque connexion réussie : il crée le compte la première fois, puis met à jour le nom et le pays.

    PismileUserService.java
    @Service
    public class PismileUserService extends OidcUserService {
    
        private final AccountRepository accounts;
    
        public PismileUserService(AccountRepository accounts) {
            this.accounts = accounts;
        }
    
        @Override
        @Transactional
        public OidcUser loadUser(OidcUserRequest request) {
            OidcUser user = super.loadUser(request);
            Account account = accounts.findByPismileSub(user.getSubject())
                    .orElseGet(() -> accounts.save(new Account(user.getSubject())));
            account.refresh(user.getFullName(),
                    user.getClaimAsString("pismile_country"),
                    user.getClaimAsString("pismile_category"));
            return user;
        }
    }
  5. Configurez la sécurité

    PKCE à l'aller, compte local au retour, déconnexion de votre site et de pismile.

    SecurityConfig.java
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig {
    
        @Bean
        SecurityFilterChain security(HttpSecurity http, ClientRegistrationRepository registrations,
                PismileUserService pismileUserService) throws Exception {
    
            DefaultOAuth2AuthorizationRequestResolver resolver =
                    new DefaultOAuth2AuthorizationRequestResolver(registrations, "/oauth2/authorization");
            resolver.setAuthorizationRequestCustomizer(OAuth2AuthorizationRequestCustomizers.withPkce());
    
            OidcClientInitiatedLogoutSuccessHandler logout = new OidcClientInitiatedLogoutSuccessHandler(registrations);
            logout.setPostLogoutRedirectUri("{baseUrl}/");
    
            http
                .authorizeHttpRequests(auth -> auth
                    .requestMatchers("/", "/error", "/css/**").permitAll()
                    .anyRequest().authenticated())
                .oauth2Login(login -> login
                    .authorizationEndpoint(endpoint -> endpoint.authorizationRequestResolver(resolver))
                    .userInfoEndpoint(userInfo -> userInfo.oidcUserService(pismileUserService))
                    .defaultSuccessUrl("/compte", true))
                .logout(out -> out.logoutSuccessHandler(logout));
            return http.build();
        }
    }
  6. Affichez le compte

    AccountController.java
    @Controller
    public class AccountController {
    
        private final AccountRepository accounts;
    
        public AccountController(AccountRepository accounts) {
            this.accounts = accounts;
        }
    
        @GetMapping("/")
        String home() {
            return "home";
        }
    
        @GetMapping("/compte")
        String account(@AuthenticationPrincipal OidcUser user, Model model) {
            model.addAttribute("account", accounts.findByPismileSub(user.getSubject()).orElseThrow());
            return "account";
        }
    }
    templates/home.html
    <a href="/oauth2/authorization/pismile">Se connecter avec pismile</a>
    templates/account.html
    <h1>Bonjour <span th:text="${account.verifiedName}">AWA MENSAH</span></h1>
    <p>
      Pays : <span th:text="${account.country}">TG</span> · Catégorie :
      <span th:text="${account.category}">P</span>
    </p>
    <form th:action="@{/logout}" method="post">
      <button type="submit">Se déconnecter</button>
    </form>
  7. Testez

    Terminal
    export PISMILE_CLIENT_SECRET=votre_secret
    ./mvnw spring-boot:run

    Ouvrez http://localhost:8090, connectez-vous avec un alias de test du sandbox BCEAO, confirmez la demande dans le playground : vous arrivez sur /compte, et une ligne apparaît dans la table accounts.

Cette page vous a-t-elle aidé ?