التخطي إلى المحتوى الرئيسي

فلتر الأمان Spring Security مع تكامل OIDC لـ Casdoor

Casdoor هو مزود هوية مفتوح المصدر يدعم 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
  • احصل على Certificate الخاص بك في صفحة تحرير الشهادة. إعداد شهادة Casdoor
  • أضف المزود والإعدادات الأخرى حسب الحاجة.

يمكنك الحصول على القيم لـ Application Name، Organization Name، Redirect URL، Client ID، Client Secret، و Certificate في صفحة إعدادات التطبيق. سنستخدمها في الخطوة التالية.

الخطوة 3: تكوين Spring Security

يمكنك تخصيص إعدادات فلاتر Spring Security لمعالجة الرموز:

تحذير

تأكد من استبدال قيم التكوين بقيم خاصة بك من مثيل Casdoor الخاص بك، خاصة <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 {
    // 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. أضف فلتر 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

بعد تسجيل الدخول، سيتم تحويلك إلى /. مورد