Passer au contenu principal

Filtre de sécurité Spring avec intégration OIDC pour Casdoor

Casdoor est un IDP open-source qui prend en charge OIDC et divers autres protocoles. Dans cet article, nous verrons comment intégrer Casdoor à votre application en utilisant le filtre de sécurité Spring et OIDC.

Étape 1 : Déployez Casdoor

Tout d'abord, vous devez déployer le serveur Casdoor. Reportez-vous à la documentation officielle pour les instructions d'installation du serveur. Après un déploiement réussi, assurez-vous que :

  • Le serveur Casdoor fonctionne à http://localhost:8000.
  • Vous pouvez voir la page de connexion Casdoor à http://localhost:7001.
  • Vous pouvez tester la fonctionnalité de connexion en vous connectant avec les identifiants admin et 123.

Après avoir vérifié ces étapes, suivez les étapes ci-dessous pour intégrer Casdoor à votre application.

Étape 2 : Configurez l'application Casdoor

  • Créez une nouvelle application Casdoor ou utilisez-en une existante.
  • Ajoutez votre URL de redirection. Vous pouvez trouver plus d'informations sur l'obtention de l'URL de redirection dans la section suivante. Paramètres de l'application Casdoor
  • Obtenez votre Certificat sur la page d'édition du certificat. Paramètres de certification Casdoor
  • Ajoutez le fournisseur et les autres paramètres selon les besoins.

Vous pouvez obtenir les valeurs pour Nom de l'application, Nom de l'organisation, URL de redirection, ID client, Secret client, et Certificat sur la page des paramètres de l'application. Nous les utiliserons à l'étape suivante.

Étape 3 : Configurez Spring Security

Vous pouvez personnaliser les paramètres des filtres Spring Security pour traiter les tokens :

prudence

Assurez-vous de remplacer les valeurs de configuration par celles de votre propre instance Casdoor, en particulier <Client ID> et les autres.

server:
port: 8080
casdoor:
endpoint: http://CASDOOR_HOSTNAME:8000
client-id: <Client ID>
client-secret: <Client Secret>
certificate: <Certificate>
organization-name: <Organization Name>
application-name: <Application Name>
redirect-url: http://FRONTEND_HOSTNAME/callback
prudence

Pour les applications frontend, la valeur par défaut de <FRONTEND_HOSTNAME> est localhost:3000. Dans cette démo, l'URL de redirection est http://localhost:3000/callback. Assurez-vous de configurer cela dans votre application casdoor.

Étape 4 : Configurez le Frontend

Vous devez installer casdoor-js-sdk et configurer le SDK comme suit :

  1. Installez casdoor-js-sdk.

    npm i casdoor-js-sdk 
    # or
    yarn add casdoor-js-sdk
  2. Configurez SDK.

    import Sdk from "casdoor-js-sdk";

    // Serverurl is the URL where spring security is deployed
    export const ServerUrl = "http://BACKEND_HOSTNAME:8080";

    const sdkConfig = {
    serverUrl: "http://CASDOOR_HOSTNAME:8000",
    clientId: "<your client id>",
    appName: "<your application name>",
    organizationName: "<your organization name>",
    redirectPath: "/callback",
    };

    export const CasdoorSDK = new Sdk(sdkConfig);

Étape 5 : Mettez en place une démo

  1. Créez une application Spring Boot.

  2. Ajoutez quelques configurations pour gérer JWT.

    @EnableWebSecurity
    public class SecurityConfig {

    private final JwtTokenFilter jwtTokenFilter;

    public SecurityConfig(JwtTokenFilter jwtTokenFilter) {
    this.jwtTokenFilter = jwtTokenFilter;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    // enable CORS and disable CSRF
    http = http.cors(corsConfig -> corsConfig
    .configurationSource(configurationSource())
    ).csrf().disable();

    // set session management to stateless
    http = http
    .sessionManagement()
    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    .and();

    // set permissions on endpoints
    http.authorizeHttpRequests(authorize -> authorize
    .mvcMatchers("/api/redirect-url", "/api/signin").permitAll()
    .mvcMatchers("/api/**").authenticated()
    );

    // set unauthorized requests exception handler
    http = http
    .exceptionHandling()
    .authenticationEntryPoint(
    (request, response, ex) -> ResponseUtils.fail(response, "unauthorized")
    )
    .and();

    // add JWT token filter
    http.addFilterBefore(
    jwtTokenFilter,
    UsernamePasswordAuthenticationFilter.class
    );
    return http.build();
    }

    // ...
}
```
  1. Ajoutez un simple filtre JWT pour intercepter les requêtes qui nécessitent une vérification de token.

    @Component
    public class JwtTokenFilter extends OncePerRequestFilter {

    private final CasdoorAuthService casdoorAuthService;

    public JwtTokenFilter(CasdoorAuthService casdoorAuthService) {
    this.casdoorAuthService = casdoorAuthService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
    HttpServletResponse response,
    FilterChain chain)
    throws ServletException, IOException {
    // get authorization header and validate
    final String header = request.getHeader(HttpHeaders.AUTHORIZATION);
    if (!StringUtils.hasText(header) || !header.startsWith("Bearer ")) {
    chain.doFilter(request, response);
    return;
    }

    // get jwt token and validate
    final String token = header.split(" ")[1].trim();

    // get user identity and set it on the spring security context
    UserDetails userDetails = null;
    try {
    CasdoorUser casdoorUser = casdoorAuthService.parseJwtToken(token);
    userDetails = new CustomUserDetails(casdoorUser);
    } catch (CasdoorAuthException exception) {
    logger.error("casdoor auth exception", exception);
    chain.doFilter(request, response);
    return;
    }

    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
    userDetails,
    null,
    AuthorityUtils.createAuthorityList("ROLE_casdoor")
    );

    authentication.setDetails(
    new WebAuthenticationDetailsSource().buildDetails(request)
    );

    SecurityContextHolder.getContext().setAuthentication(authentication);
    chain.doFilter(request, response);
    }

    }

    Lorsque l'utilisateur accède à l'interface nécessitant une authentification, JwtTokenFilter obtiendra le token de l'en-tête de la requête Authorization et le vérifiera.

  2. Définissez un Controller pour gérer lorsque l'utilisateur se connecte à Casdoor. Après la connexion de l'utilisateur, il sera redirigé vers le serveur et portera le code et le state. Le serveur doit alors vérifier l'identité de l'utilisateur auprès de Casdoor et obtenir le token à travers ces deux paramètres.

    @RestController
    public class UserController {

    private static final Logger logger = LoggerFactory.getLogger(UserController.class);

    private final CasdoorAuthService casdoorAuthService;

    // ...
    @PostMapping("/api/signin")
public Result signin(@RequestParam("code") String code, @RequestParam("state") String state) {
try {
String token = casdoorAuthService.getOAuthToken(code, state);
return Result.success(token);
} catch (CasdoorAuthException exception) {
logger.error("casdoor auth exception", exception);
return Result.failure(exception.getMessage());
}
}

// ...
}
```

Étape 6 : Essayez la démo

Vous pouvez accéder à l'application frontend via votre navigateur. Si vous n'êtes pas connecté, vous verrez un bouton de connexion. Cliquez dessus, et vous serez redirigé vers la page de connexion Casdoor.

Si vous visitez votre page racine,bienvenue

Cliquez sur le bouton Connexion Casdoor, et la page vous redirigera vers la page de connexion de Casdoor. casdoor

Après vous être connecté, vous serez redirigé vers /. ressource