ข้ามไปยังเนื้อหาหลัก

Spring Security Filter ที่มีการรวม OIDC สำหรับ Casdoor

Casdoor เป็น IDP โอเพนซอร์สที่รองรับ OIDC และโปรโตคอลอื่นๆ อีกหลายอย่าง ในบทความนี้ เราจะดูวิธีการรวม Casdoor เข้ากับแอปพลิเคชันของคุณโดยใช้ Spring Security Filter และ 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, ค่าเริ่มต้นของ <FRONTEND_HOSTNAME> คือ localhost:3000 ในตัวอย่างนี้ URL สำหรับการเปลี่ยนเส้นทางคือ http://localhost:3000/callback ตรวจสอบให้แน่ใจว่าคุณได้กำหนดค่านี้ในแอปพลิเคชัน casdoor ของคุณ

ขั้นตอนที่ 4: กำหนดค่า Frontend

คุณต้องติดตั้ง 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: ทดลองใช้ตัวอย่างการทำงาน

คุณสามารถเข้าถึงแอปพลิเคชัน frontend ผ่านเบราว์เซอร์ของคุณ หากคุณยังไม่ได้ล็อกอิน คุณจะเห็นปุ่มล็อกอิน คลิกที่นั้น และคุณจะถูกเปลี่ยนเส้นทางไปยังหน้าล็อกอิน Casdoor

หากคุณเยี่ยมชมหน้า root ของคุณยินดีต้อนรับ

คลิกที่ปุ่ม Casdoor Login และหน้าเว็บจะเปลี่ยนไปยังหน้าล็อกอินของ Casdoor casdoor

หลังจากล็อกอินแล้ว คุณจะถูกเปลี่ยนทิศทางไปยัง / ทรัพยากร