Перейти к основному содержанию

Фильтр Spring Security с интеграцией OIDC для Casdoor

Casdoor - это открытый IDP, поддерживающий OIDC и различные другие протоколы. В этой статье мы увидим, как интегрировать Casdoor с вашим приложением с использованием фильтра Spring Security и OIDC.

Шаг 1: Развертывание Casdoor

Сначала вам нужно развернуть сервер Casdoor. Обратитесь к официальной документации для инструкций по установке сервера. После успешного развертывания убедитесь, что:

  • Сервер Casdoor работает по адресу http://localhost:8000.
  • Вы можете увидеть страницу входа Casdoor по адресу http://localhost:7001.
  • Вы можете протестировать функциональность входа, войдя с учетными данными admin и 123.

После проверки этих шагов следуйте приведенным ниже инструкциям, чтобы интегрировать Casdoor с вашим приложением.

Шаг 2: Настройка приложения Casdoor

  • Создайте новое приложение Casdoor или используйте существующее.
  • Добавьте ваш URL перенаправления. Более подробную информацию о получении URL перенаправления вы найдете в следующем разделе. Настройка приложения Casdoor
  • Получите ваш Сертификат на странице редактирования сертификата. Настройка сертификации Casdoor
  • Добавьте провайдера и другие настройки по мере необходимости.

Вы можете получить значения для Имя приложения, Имя организации, URL перенаправления, Client ID, Client Secret и Сертификат на странице настроек приложения. Мы будем использовать их на следующем шаге.

Шаг 3: Настройка Spring Security

Вы можете настроить параметры фильтров Spring Security для обработки токенов:

осторожно

Убедитесь, что вы заменили значения конфигурации на свои собственные, особенно <Client ID> и другие.

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
осторожно

Для фронтенд-приложений значение по умолчанию для <FRONTEND_HOSTNAME> - localhost:3000. В этом демо URL перенаправления - http://localhost:3000/callback. Убедитесь, что вы настроили это в вашем приложении casdoor.

Шаг 4: Настройка фронтенда

Вам нужно установить casdoor-js-sdk и настроить SDK следующим образом:

  1. Установите casdoor-js-sdk.

    npm i casdoor-js-sdk 
    # or
    yarn add casdoor-js-sdk
  2. Настройте 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);

Шаг 5: Настройка демонстрационного примера

  1. Создайте приложение Spring Boot.

  2. Добавьте некоторые конфигурации для обработки JWT.

    @EnableWebSecurity
    public class SecurityConfig {

    private final JwtTokenFilter jwtTokenFilter;

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

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    // включить CORS и отключить CSRF
    http = http.cors(corsConfig -> corsConfig
    .configurationSource(configurationSource())
    ).csrf().disable();

    // установить управление сессиями как безсостояние
    http = http
    .sessionManagement()
    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    .and();

    // установить разрешения на конечные точки
    http.authorizeHttpRequests(authorize -> authorize
    .mvcMatchers("/api/redirect-url", "/api/signin").permitAll()
    .mvcMatchers("/api/**").authenticated()
    );

    // установить обработчик исключений для неавторизованных запросов
    http = http
    .exceptionHandling()
    .authenticationEntryPoint(
    (request, response, ex) -> ResponseUtils.fail(response, "unauthorized")
    )
    .and();

    // добавить фильтр токенов JWT
    http.addFilterBefore(
    jwtTokenFilter,
    UsernamePasswordAuthenticationFilter.class
    );
    return http.build();
    }

    // ...
}
```
  1. Добавьте простой JWT фильтр для перехвата запросов, требующих проверки токена.

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

    }

    Когда пользователь обращается к интерфейсу, требующему аутентификации, JwtTokenFilter получает токен из заголовка запроса Authorization и проверяет его.

  2. Определите Controller для обработки входа пользователя в Casdoor. После входа пользователя он будет перенаправлен на сервер и несет code и state. Сервер затем должен проверить личность пользователя из Casdoor и получить token через эти два параметра.

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

// ...
}
```

Шаг 6: Попробуйте демонстрационный пример

Вы можете получить доступ к фронтенд-приложению через ваш браузер. Если вы не вошли в систему, вы увидите кнопку входа. Нажмите на нее, и вы будете перенаправлены на страницу входа Casdoor.

Если вы посетите вашу корневую страницу,добро пожаловать

Нажмите кнопку Casdoor Login, и страница перенаправит вас на страницу входа Casdoor. casdoor

После входа в систему вы будете перенаправлены на /. ресурс