Rumah > Java > Mengamankan Spring Boot REST API untuk titik akhir yang berbeza menggunakan AAD dan AWS Cognito

Mengamankan Spring Boot REST API untuk titik akhir yang berbeza menggunakan AAD dan AWS Cognito

王林
Lepaskan: 2024-02-22 13:22:06
ke hadapan
1093 orang telah melayarinya

editor php Baicao telah menulis artikel Soal Jawab Java dengan teliti untuk anda tentang menggunakan AAD dan AWS Cognito untuk melindungi Spring Boot REST API. Dalam artikel ini, kami akan meneroka cara memanfaatkan kedua-dua perkhidmatan pengesahan ini untuk melindungi titik akhir yang berbeza dan memastikan API anda selamat dan terjamin. Ikuti panduan kami dan ketahui cara melaksanakan pengesahan dan kebenaran dalam projek Spring Boot anda untuk menjadikan API REST anda lebih berkuasa dan boleh dipercayai.

Kandungan soalan

Semoga seseorang dapat membantu saya di sini kerana saya tidak dapat mencari sebarang sumber mengenai topik ini di mana-mana sahaja.

Saya mempunyai restapi but spring, dan konfigurasi semasa mempunyai dua laluan: 1. Tidak dibenarkan 2. Diizinkan melalui pembawa aad/entra

Kaedah konfigurasi saya pada masa ini disediakan seperti berikut:

@override
protected void configure(httpsecurity http) throws exception {
        super.configure(http);
        http.csrf().disable();
        http.authorizerequests(requests -> requests
                .antmatchers(httpmethod.options, "/**/**").permitall()
                .antmatchers("/api/protected/**").fullyauthenticated()
                .anyrequest().permitall()
        );
}
Salin selepas log masuk

Ia dibungkus dalam kelas yang memanjang aadresourceserverwebsecurityconfigureradapter.

Dengan mengkonfigurasi api kami dengan cara ini, kami dapat menjamin laluan kami seperti berikut:

@preauthorize("hasauthority('approle_appname.rolename')")
@getmapping(value = "/some-method", produces = mediatype.application_json_value)
public responseentity<list<string>> getstrings() {
    return responseentity.ok(...);
}
Salin selepas log masuk

Api kami kini perlu dilanjutkan untuk membolehkan jenis pengguna baharu menggunakan titik akhir kebenaran. Pengguna ini diuruskan oleh aws cognito. Bagaimanakah cara saya menyediakan websecurityconfigureradapter saya untuk membenarkan beberapa laluan tidak dibenarkan, beberapa laluan dilindungi melalui aad dan beberapa laluan untuk dilindungi melalui aws cognito?

Masalah utama yang saya nampak ialah aadresourceserverwebsecurityconfigureradapter mengkonfigurasi pengesahan jwt sedemikian rupa sehingga ia hanya berfungsi dengan pembawa yang disediakan oleh microsoft.

Sebaik-baiknya saya ingin sesuatu seperti ini:

@configuration
@enablewebsecurity
@enableglobalmethodsecurity(prepostenabled = true)
public class securityconfig extends websecurityconfigureradapter { 

    @configuration
    @order(1)
    public static class azureadsecurityconfig extends aadresourceserverwebsecurityconfigureradapter {

        @override
        protected void configure(httpsecurity http) throws exception {
            http.authorizerequests(requests -> requests
                    .antmatchers("/api/aad/**").fullyauthenticated()
            );
            http.oauth2resourceserver().jwt([utilize aad jwt validation]);
        }

    }

    @configuration
    @order(2)
    public static class awscognitosecurityconfig extends websecurityconfigureradapter {

        @override
        protected void configure(httpsecurity http) throws exception {
            http.authorizerequests(requests -> requests
                    .antmatchers("/api/cognito/**").fullyauthenticated()
            );
            http.oauth2resourceserver().jwt([utilize aws cognito jwt validation]);
        }
    }

    @configuration
    @order(3)
    public static class defaultsecurityconfig extends websecurityconfigureradapter {

            @override
            protected void configure(httpsecurity http) throws exception {
                http.csrf().disable();
                http.authorizerequests(requests -> requests
                        .antmatchers(httpmethod.options, "/**/**").permitall()
                        .anyrequest().permitall()
                );
            }
    }

}

Salin selepas log masuk

Satu lagi isu yang saya temui ialah aadresourceserverwebsecurityconfigureradapter secara automatik menetapkan semua kemungkinan awalan untuk jwtclaimnames "peranan" dan "scp" kepada "skop_" dan "approle_". Sebaik-baiknya saya ingin mereka berbeza untuk aad dan aws kognito supaya saya awalan "aad_scope_", "aad_approle_" dan "cognito_group_".

Saya menemui beberapa maklumat yang menerangkan cara melaksanakan pengesahan jwt berbilang penyewa untuk but spring, tetapi mereka semua hanya menggunakan pangkalan data sql untuk melaksanakan pengesahan berasaskan kata laluan/pengguna.

Adakah terdapat cara di mana saya pada asasnya perlu melaksanakan semula semua logik iklan supaya saya boleh mencampurkan pengesahan jwt yang diberikan oleh aws cognito, atau adakah terdapat cara untuk membuat keputusan berdasarkan penghalaan?

Saya sudah tahu bahawa anda boleh mengkonfigurasi penggunaan jwt dalam fungsi httpsecurity 上使用 oauth2resourceserver(), tetapi saya hanya menemui maklumat tentang cara melaksanakan fungsi itu untuk penyewa tunggal.

Jika sesiapa telah berjaya melaksanakan kes khusus atau serupa ini, atau boleh mendorong saya ke arah yang betul, saya amat berterima kasih. Atau mungkin idea saya salah sama sekali, jadi tolong beritahu saya.

Menggunakan Kemas Kini Penyelesaian Kerja (25 Januari 2024)

Terima kasih kepada @ch4mp atas jawapannya, saya telah berjaya. >Jawapan Berfungsi<

Pelaksanaan saya kini sangat dipermudahkan dan kelihatan seperti ini:

permohonan.yml

com:
  c4-soft:
    springaddons:
      oidc:
        ops:
          - iss: https://cognito-idp.<region>.amazonaws.com/<cognito-pool>
            authorities:
              - path: $.cognito:groups
                prefix: cognito_group_
          - iss: https://sts.windows.net/<entra objectid>/
            authorities:
              - path: $.roles.*
                prefix: aad_approle_
              - path: $.scp
                prefix: aad_scope_
            aud: <enterprise application id>
        resource-server:
          permit-all:
            - /api/route/noauth
Salin selepas log masuk

Konfigurasi keselamatan

package some.package;

import org.springframework.context.annotation.configuration;
import org.springframework.security.config.annotation.method.configuration.enablemethodsecurity;
import org.springframework.security.config.annotation.web.configuration.enablewebsecurity;

@enablewebsecurity
@enablemethodsecurity
@configuration
public class securityconfig { }

Salin selepas log masuk

Pengawal saya kini kelihatan seperti ini:

package some.package;


import org.springframework.http.responseentity;
import org.springframework.security.access.prepost.preauthorize;
import org.springframework.security.core.context.securitycontextholder;
import org.springframework.security.oauth2.jwt.jwt;
import org.springframework.web.bind.annotation.getmapping;
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.bind.annotation.restcontroller;

@restcontroller
@requestmapping("/api/route")
public class jwttestcontroller {

    @getmapping("/aadauth")
    @preauthorize("hasauthority('aad_approle_grantedapprole.xxx')")
    public responseentity<string> aadauthrole() {
        jwt jwt = (jwt) securitycontextholder.getcontext().getauthentication().getprincipal();
        return responseentity.ok(jwt.getclaims().tostring());
    }

    @getmapping("/aadauth")
    @preauthorize("hasauthority('aad_scope_grantedscope.xxx')")
    public responseentity<string> aadauthscope() {
        jwt jwt = (jwt) securitycontextholder.getcontext().getauthentication().getprincipal();
        return responseentity.ok(jwt.getclaims().tostring());
    }

    @preauthorize("hasauthority('cognito_group_somegroup')")
    @getmapping("/cognitoauth")
    public responseentity<string> cognitoauth() {
        jwt jwt = (jwt) securitycontextholder.getcontext().getauthentication().getprincipal();
        return responseentity.ok(jwt.getclaims().tostring());
    }

    @getmapping("/noauth")
    public responseentity<string> noauth() {
        return responseentity.ok("hello world!");
    }

}

Salin selepas log masuk

build.gradle

implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
    implementation 'com.c4-soft.springaddons:spring-addons-starter-oidc:7.3.5'
Salin selepas log masuk

Ini bukan pelancar rasmi musim bunga, tetapi pelaksanaan oss: https://www.php.cn/link/49844ba129a1cbc3d964703fcdb756ba

Saya akan mengemas kini sekali lagi jika saya menghadapi sebarang isu lain, tetapi buat masa ini ia berfungsi.

Penyelesaian

Saya akan dedahkan penyelesaian di sini menggunakan pemula saya kerana ia lebih mudah.

Jika anda memilih untuk hanya menggunakan pemula but spring "rasmi" untuk membina konfigurasi keselamatan anda, anda mesti menggunakan iss 声明提供自己的 authenticationmanagerresolver<httpservletrequest>, setiap pengurus pengesahan mempunyai penukar pengesahan sendiri dan penukar kebenaran sendiri untuk mengendalikan tuntutan sumber dan anda mahukan awalan yang diperlukan. Semak imbas tutorial saya atau dokumentasi rasmi untuk contoh dan petua pelaksanaan. Jawapan lain ini juga mungkin membantu (keperluan pemetaan kebenaran adalah berbeza sama sekali, tetapi penyelesai pengurus pengesahan adalah serupa).

Gunakan but 3.2.2 dan spring-addons

<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
    xsi:schemalocation="http://maven.apache.org/pom/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelversion>4.0.0</modelversion>
    <parent>
        <groupid>org.springframework.boot</groupid>
        <artifactid>spring-boot-starter-parent</artifactid>
        <version>3.2.2</version>
        <relativepath/> <!-- lookup parent from repository -->
    </parent>
    <groupid>com.c4-soft.demo</groupid>
    <artifactid>multi-tenant-resource-server</artifactid>
    <version>0.0.1-snapshot</version>

    <properties>
        <java.version>21</java.version>
        <spring-addons.version>7.3.5</spring-addons.version>
    </properties>

    <dependencies>
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-oauth2-resource-server</artifactid>
        </dependency>
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-web</artifactid>
        </dependency>
        <dependency>
            <groupid>com.c4-soft.springaddons</groupid>
            <artifactid>spring-addons-starter-oidc</artifactid>
            <version>${spring-addons.version}</version>
        </dependency>

        <dependency>
            <groupid>com.c4-soft.springaddons</groupid>
            <artifactid>spring-addons-starter-oidc-test</artifactid>
            <version>${spring-addons.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupid>org.springframework.boot</groupid>
                <artifactid>spring-boot-maven-plugin</artifactid>
            </plugin>
        </plugins>
    </build>

</project>
Salin selepas log masuk
@configuration
@enablemethodsecurity
public class securityconf {
}
Salin selepas log masuk

Edit yang berikut application.yaml untuk menempatkan penerbit anda sendiri:

com:
  c4-soft:
    springaddons:
      oidc:
        ops:
        - iss: https://cognito-idp.us-west-2.amazonaws.com/us-west-2_rzhmglwjl
          authorities:
          - path: $.cognito:groups
            prefix: cognito_group_
        - iss: https://sts.windows.net/0a962d63-6b23-4416-81a6-29f88c553998/
          authorities:
          - path: $.approles.*.displayname
            prefix: aad_approle_
          - path: $.scope
            prefix: aad_scope_
        resourceserver:
          # spring-addons whitelist is for permitall() (rather than isauthenticated())
          # which is probably much safer
          permit-all:
          - /actuator/health/readiness
          - /actuator/health/liveness
          - /v3/api-docs/**
          - /api/public/**
Salin selepas log masuk

Nilai path di atas ialah laluan json. Anda boleh menggunakan alatan seperti jsonpath.com untuk menguji ungkapan laluan terhadap muatan token anda sendiri (diekstrak menggunakan alatan seperti jwt.io).

Ya, semudah itu. Tidak, saya tidak meninggalkan sebarang sifat yaml atau konfigurasi java (jika anda tidak percaya saya, hanya mengujinya dalam projek baharu).

示例控制器

@restcontroller
public class greetcontroller {

    @getmapping("/greet")
    @preauthorize("isauthenticated()")
    public string getgreet(authentication auth) {
        return "hello %s! you are granted with %s.".formatted(auth.getname(), auth.getauthorities());
    }

    @getmapping(value = "/strings")
    @preauthorize("hasanyauthority('aad_approle_admin', 'cognito_group_admin')")
    public list<string> getstrings() {
        return list.of("protected", "strings");
    }
}
Salin selepas log masuk

示例测试

@webmvctest(controllers = greetcontroller.class)
@autoconfigureaddonswebmvcresourceserversecurity
@import(securityconf.class)
class greetcontrollertest {
    @autowired
    mockmvcsupport api;

    @test
    @withanonymoususer
    void givenuserisanonymous_whengetgreet_thenunauthorized() throws unsupportedencodingexception, exception {
        api.get("/greet").andexpect(status().isunauthorized());
    }

    @test
    @withjwt("aad_admin.json")
    void givenuserisaadadmin_whengetgreet_thenok() throws unsupportedencodingexception, exception {
        final var actual = api.get("/greet").andexpect(status().isok()).andreturn().getresponse().getcontentasstring();
        assertequals(
            "hello aad-admin! you are granted with [aad_approle_msiam_access, aad_approle_admin, aad_scope_openid, aad_scope_profile, aad_scope_machin:truc].",
            actual);
    }

    @test
    @withjwt("cognito_admin.json")
    void givenuseriscognitoadmin_whengetgreet_thenok() throws unsupportedencodingexception, exception {
        final var actual = api.get("/greet").andexpect(status().isok()).andreturn().getresponse().getcontentasstring();
        assertequals("hello amazon-cognito-admin! you are granted with [cognito_group_admin, cognito_group_machin:truc].", actual);
    }

    @test
    @withjwt("aad_machin-truc.json")
    void givenuserisaadmachintruc_whengetgreet_thenok() throws unsupportedencodingexception, exception {
        final var actual = api.get("/greet").andexpect(status().isok()).andreturn().getresponse().getcontentasstring();
        assertequals("hello aad-user! you are granted with [aad_approle_msiam_access, aad_scope_openid, aad_scope_profile, aad_scope_machin:truc].", actual);
    }

    @test
    @withjwt("cognito_machin-truc.json")
    void givenuseriscognitomachintruc_whengetgreet_thenok() throws unsupportedencodingexception, exception {
        final var actual = api.get("/greet").andexpect(status().isok()).andreturn().getresponse().getcontentasstring();
        assertequals("hello amazon-cognito-user! you are granted with [cognito_group_machin:truc].", actual);
    }

    @test
    @withanonymoususer
    void givenuserisanonymous_whengetstrings_thenunauthorized() throws unsupportedencodingexception, exception {
        api.get("/strings").andexpect(status().isunauthorized());
    }

    @test
    @withjwt("aad_admin.json")
    void givenuserisaadadmin_whengetstrings_thenok() throws unsupportedencodingexception, exception {
        final var actual = api.get("/strings").andexpect(status().isok()).andreturn().getresponse().getcontentasstring();
        assertequals("[\"protected\",\"strings\"]", actual);
    }

    @test
    @withjwt("cognito_admin.json")
    void givenuseriscognitoadmin_whengetstrings_thenok() throws unsupportedencodingexception, exception {
        final var actual = api.get("/strings").andexpect(status().isok()).andreturn().getresponse().getcontentasstring();
        assertequals("[\"protected\",\"strings\"]", actual);
    }

    @test
    @withjwt("aad_machin-truc.json")
    void givenuserisaadmachintruc_whengetstrings_thenforbidden() throws unsupportedencodingexception, exception {
        api.get("/strings").andexpect(status().isforbidden());
    }

    @test
    @withjwt("cognito_machin-truc.json")
    void givenuseriscognitomachintruc_whengetstrings_thenforbidden() throws unsupportedencodingexception, exception {
        api.get("/strings").andexpect(status().isforbidden());
    }

}
Salin selepas log masuk

使用此测试资源:

  • aad_admin.json
{
    "sub": "aad-admin",
    "iss": "https://sts.windows.net/0a962d63-6b23-4416-81a6-29f88c553998/",
    "approles": [
        {
          "allowedmembertypes": [
            "user"
          ],
          "description": "msiam_access",
          "displayname": "msiam_access",
          "id": "ef7437e6-4f94-4a0a-a110-a439eb2aa8f7",
          "isenabled": true,
          "origin": "application",
          "value": null
        },
        {
          "allowedmembertypes": [
            "user"
          ],
          "description": "administrators only",
          "displayname": "admin",
          "id": "4f8f8640-f081-492d-97a0-caf24e9bc134",
          "isenabled": true,
          "origin": "serviceprincipal",
          "value": "administrator"
        }
    ],
    "scope": "openid profile machin:truc"
}
Salin selepas log masuk
  • aad_machin-truc.json
{
    "sub": "aad-user",
    "iss": "https://sts.windows.net/0a962d63-6b23-4416-81a6-29f88c553998/",
    "approles": [
        {
          "allowedmembertypes": [
            "user"
          ],
          "description": "msiam_access",
          "displayname": "msiam_access",
          "id": "ef7437e6-4f94-4a0a-a110-a439eb2aa8f7",
          "isenabled": true,
          "origin": "application",
          "value": null
        }
    ],
    "scope": "openid profile machin:truc"
}
Salin selepas log masuk
  • cognito_admin.json
{
    "sub": "amazon-cognito-admin",
    "iss": "https://cognito-idp.us-west-2.amazonaws.com/us-west-2_rzhmglwjl",
    "cognito:groups": ["admin", "machin:truc"],
    "scope": "openid profile cog:scope"
}
Salin selepas log masuk
  • cognito_machin-truc.json
{
    "sub": "amazon-cognito-user",
    "iss": "https://cognito-idp.us-west-2.amazonaws.com/us-west-2_RzhmgLwjl",
    "cognito:groups": ["machin:truc"],
    "scope": "openid profile cog:scope"
}
Salin selepas log masuk

Atas ialah kandungan terperinci Mengamankan Spring Boot REST API untuk titik akhir yang berbeza menggunakan AAD dan AWS Cognito. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan