Saltar al contenido principal

Filtro de Seguridad Spring con integración OIDC para Casdoor

Casdoor es un IDP de código abierto que soporta OIDC y varios otros protocolos. En este artículo, veremos cómo integrar Casdoor con tu aplicación usando el Filtro de Seguridad Spring y OIDC.

Paso 1: Desplegar Casdoor

Primero, necesitas desplegar el servidor Casdoor. Consulta la documentación oficial para instrucciones de instalación del servidor. Después del despliegue exitoso, asegúrate de que:

  • El servidor Casdoor está funcionando en http://localhost:8000.
  • Puedes ver la página de inicio de sesión de Casdoor en http://localhost:7001.
  • Puedes probar la funcionalidad de inicio de sesión iniciando sesión con las credenciales admin y 123.

Después de verificar estos pasos, sigue los pasos a continuación para integrar Casdoor con tu aplicación.

Paso 2: Configurar la Aplicación Casdoor

  • Crea una nueva aplicación Casdoor o usa una existente.
  • Agrega tu URL de redirección. Puedes encontrar más información sobre cómo obtener la URL de redirección en la siguiente sección. Configuración de la Aplicación Casdoor
  • Obtén tu Certificado en la página de edición de certificados. Configuración de Certificación Casdoor
  • Agrega el proveedor y otros ajustes según sea necesario.

Puedes obtener los valores para Nombre de la Aplicación, Nombre de la Organización, URL de Redirección, ID del Cliente, Secreto del Cliente y Certificado en la página de configuración de la aplicación. Los usaremos en el siguiente paso.

Paso 3: Configurar Spring Security

Puedes personalizar la configuración de los filtros de Spring Security para procesar tokens:

precaución

Asegúrate de reemplazar los valores de configuración con los de tu propia instancia de Casdoor, especialmente <Client ID> y los demás.

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
precaución

Para aplicaciones frontend, el valor predeterminado de <FRONTEND_HOSTNAME> es localhost:3000. En esta demostración, la URL de redirección es http://localhost:3000/callback. Asegúrate de configurar esto en tu aplicación casdoor.

Paso 4: Configurar Frontend

Necesitas instalar casdoor-js-sdk y configurar el SDK de la siguiente manera:

  1. Instalar casdoor-js-sdk.

    npm i casdoor-js-sdk 
    # or
    yarn add casdoor-js-sdk
  2. Configurar 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);

Paso 5: Configurar una Demostración

  1. Crea una aplicación Spring Boot.

  2. Agrega algunas configuraciones para manejar 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. Agrega un filtro JWT simple para interceptar solicitudes que requieren verificación 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);
    }

    }

    Cuando el usuario accede a la interfaz que requiere autenticación, JwtTokenFilter obtendrá el token del encabezado de la solicitud Authorization y lo verificará.

  2. Define un Controller para manejar cuando el usuario inicia sesión en Casdoor. Después de que el usuario inicie sesión, será redirigido al servidor y llevará el code y el state. El servidor entonces necesita verificar la identidad del usuario desde Casdoor y obtener el token a través de estos dos parámetros.

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

// ...
}
```

Paso 6: Probar la Demostración

Puedes acceder a la aplicación frontend a través de tu navegador. Si no has iniciado sesión, verás un botón de inicio de sesión. Haz clic en él, y serás redirigido a la página de inicio de sesión de Casdoor.

Si visitas tu página raíz,bienvenido

Haz clic en el botón Iniciar Sesión Casdoor, y la página te redirigirá a la página de inicio de sesión de Casdoor. casdoor

Después de iniciar sesión, serás redirigido a /. recurso