亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

通過 Spring Boot Keycloak 集成的 OAuth2 客戶端憑據流

通過 Spring Boot Keycloak 集成的 OAuth2 客戶端憑據流

月關寶盒 2023-08-04 16:43:32
我的申請包括:后端/資源服務器網絡應用程序用戶界面鑰匙斗篷UI 使用具有授權代碼授權流程的 keycloak 客戶端通過 RESTful API 與后端服務器進行通信。這工作正?!,F在,我需要使用系統/服務帳戶(通常具有比用戶更多的權限)訪問后端資源的額外可能性。您將如何實現這一要求?我認為客戶端憑證流程在這里會很有用。是否可以將 OAuth2 客戶端憑據流與 Spring Boot 的 keycloak 客戶端一起使用?我找到了使用 Spring Security OAuth2 客戶端功能來實現客戶端憑據流的示例,但這感覺很奇怪,因為我已經使用 keycloak 客戶端來處理 OAuth 事務。編輯:解決方案感謝您的回答對我幫助很大。在我的 UI Web 應用程序中,我現在可以通過使用經過身份驗證的用戶 OAuth2 令牌或使用我的 UI 服務帳戶的客戶端憑據流中的令牌與后端進行通信。每種方式都有自己的方式RestTemplate,第一種是通過 keycloak 集成完成的,第二種是由 Spring Security OAuth2 完成的。
查看完整描述

3 回答

?
湖上湖

TA貢獻2003條經驗 獲得超2個贊

是的,您可以使用 OAuth 2.0 客戶端憑據流程和服務帳戶。

Keycloak 建議使用 3 種方法來保護 SpringBoot REST 服務的安全:

  1. 帶有 Keycloak Spring Boot 適配器

  2. 帶 keycloak Spring 安全適配器

  3. 與 OAuth2 / OpenID 連接

請注意將您的客戶端配置為:

  • 訪問類型:機密

  • 授權:已啟用

  • 服務帳戶(OAuth 客戶端憑據流程):已啟用

請注意將您的目標服務配置為:

  • 訪問類型:僅承載

因此,調用者應該是confidential,目標服務應該是bearer-only。

創建您的用戶、角色、映射器...并將角色分配給您的用戶。

檢查您的 spring 項目中是否有此依賴項:

<dependency>

? <groupId>org.springframework.boot</groupId>

? <artifactId>spring-boot-starter-security</artifactId>

</dependency>

<dependency>

? <groupId>org.springframework.security.oauth.boot</groupId>

? <artifactId>spring-security-oauth2-autoconfigure</artifactId>

</dependency>

配置要在 REST 客戶端 (application.properties) 中使用的身份驗證,例如:


security.oauth2.client.client-id=employee-service

security.oauth2.client.client-secret=68977d81-c59b-49aa-aada-58da9a43a850

security.oauth2.client.user-authorization-uri=${rest.security.issuer-uri}/protocol/openid-connect/auth

security.oauth2.client.access-token-uri=${rest.security.issuer-uri}/protocol/openid-connect/token

security.oauth2.client.scope=openid

security.oauth2.client.grant-type=client_credentials

JwtAccessTokenCustomizer像 Arun 的示例一樣實現您的SecurityConfigurer (ResourceServerConfigurerAdapter) 。


最后實現你的服務控制器:


@RestController

@RequestMapping("/api/v1/employees")

public class EmployeeRestController {


? @GetMapping(path = "/username")

? @PreAuthorize("hasAnyAuthority('ROLE_USER')")

? public ResponseEntity<String> getAuthorizedUserName() {

? ? return ResponseEntity.ok(SecurityContextUtils.getUserName());

? }


? @GetMapping(path = "/roles")

? @PreAuthorize("hasAnyAuthority('ROLE_USER')")

? public ResponseEntity<Set<String>> getAuthorizedUserRoles() {

? ? return ResponseEntity.ok(SecurityContextUtils.getUserRoles());

? }

}


查看完整回答
反對 回復 2023-08-04
?
眼眸繁星

TA貢獻1873條經驗 獲得超9個贊

按照@dmitri-algazin 實施工作流程,您基本上有兩個選擇:


如果您想涵蓋除 Keycloak 之外的其他 IdM,它以某種方式解決了單一責任原則,我會使用RestTemplate. 您可以在下面找到變量:

    //Constants

    @Value("${keycloak.url}")

    private String keycloakUrl;


    @Value("${keycloak.realm}")

    private String keycloakRealm;


    @Value("${keycloak.client_id}")

    private String keycloakClientId;


    RestTemplate restTemplate = new RestTemplate();

    private static final String BEARER = "BEARER ";

首先,您需要生成訪問令牌:


    @Override

    public AccessTokenResponse login(KeycloakUser user) throws NotAuthorizedException {

        try {

            String uri = keycloakUrl + "/realms/" + keycloakRealm + 

                    "/protocol/openid-connect/token";

            String data = "grant_type=password&username="+

                    user.getUsername()+"&password="+user.getPassword()+"&client_id="+

                    keycloakClientId;


            HttpHeaders headers = new HttpHeaders();

            headers.set("Content-Type", "application/x-www-form-urlencoded");


            HttpEntity<String> entity = new HttpEntity<String>(data, headers);

            ResponseEntity<AccessTokenResponse> response = restTemplate.exchange(uri, 

                    HttpMethod.POST, entity, AccessTokenResponse.class);            


            if (response.getStatusCode().value() != HttpStatus.SC_OK) {

                log.error("Unauthorised access to protected resource", response.getStatusCode().value());

                throw new NotAuthorizedException("Unauthorised access to protected resource");

            }

            return response.getBody();

        } catch (Exception ex) {

            log.error("Unauthorised access to protected resource", ex);

            throw new NotAuthorizedException("Unauthorised access to protected resource");

        } 

    }

然后使用令牌,您可以從用戶那里檢索信息:


    @Override

    public String user(String authToken) throws NotAuthorizedException {


        if (! authToken.toUpperCase().startsWith(BEARER)) {

            throw new NotAuthorizedException("Invalid OAuth Header. Missing Bearer prefix");

        }


        HttpHeaders headers = new HttpHeaders();

        headers.set("Authorization", authToken);


        HttpEntity<String> entity = new HttpEntity<>(headers);


        ResponseEntity<AccessToken> response = restTemplate.exchange(

                keycloakUrl + "/realms/" + keycloakRealm + "/protocol/openid-connect/userinfo", 

                HttpMethod.POST, 

                entity, 

                AccessToken.class);


        if (response.getStatusCode().value() != HttpStatus.SC_OK) {

            log.error("OAuth2 Authentication failure. "

                    + "Invalid OAuth Token supplied in Authorization Header on Request. Code {}", response.getStatusCode().value());

            throw new NotAuthorizedException("OAuth2 Authentication failure. "

                    + "Invalid OAuth Token supplied in Authorization Header on Request.");

        }


        log.debug("User info: {}", response.getBody().getPreferredUsername());

        return response.getBody().getPreferredUsername();

    }

您可以將此 URL 替換為 @dimitri-algazin 提供的 URL,以檢索所有用戶信息。


可以使用 Keycloak 依賴項:

        <!-- keycloak -->

        <dependency>

            <groupId>org.keycloak</groupId>

            <artifactId>keycloak-admin-client</artifactId>

            <version>3.4.3.Final</version>

        </dependency>


        <dependency>

            <groupId>org.jboss.resteasy</groupId>

            <artifactId>resteasy-client</artifactId>

            <version>3.1.4.Final</version>

        </dependency>

并使用類來生成令牌:


            Keycloak keycloak = KeycloakBuilder

                    .builder()

                    .serverUrl(keycloakUrl)

                    .realm(keycloakRealm)

                    .username(user.getUsername())

                    .password(user.getPassword())

                    .clientId(keycloakClientId)

                    .resteasyClient(new ResteasyClientBuilder().connectionPoolSize(10).build())

                    .build();


            return keycloak.tokenManager().getAccessToken();

示例摘自此處。我們還將鏡像上傳到 Docker Hub,以方便與 Keycloak 交互。因此我們從選項 2) 開始。目前,我們正在覆蓋其他 IdM,我們選擇了選項 1),以避免包含額外的依賴項。結論:


如果您堅持使用 Keycloak,我會選擇選項 2 ,因為類包含 Keycloak 工具的額外功能。我會選擇選項 1以獲得更多的覆蓋范圍和其他 OAuth 2.0 工具。


查看完整回答
反對 回復 2023-08-04
?
瀟瀟雨雨

TA貢獻1833條經驗 獲得超4個贊

我們有類似的需求,通過用戶 uuid 獲取用戶電子郵件。

創建服務用戶,確保用戶具有“領域管理”->“查看用戶”角色(也可能是查詢用戶)

過程很簡單:使用服務用戶登錄 keycloak(將密碼和/或用戶名編碼在屬性文件中),使用授權標頭中的 accessToken 向 keycloak 發出請求

獲取 http://{yourdomainadress}/auth/admin/realms/{yourrealmname}/users/{userId}

使用REST API登錄keycloak的方法:

POST http://{yourdomainadress}/auth/realms/{yourrealmname}/protocol/openid-connect/token

標題:

內容類型:application/x-www-form-urlencoded

正文 x-www-form-urlencoded:

client_id:您的客戶

用戶名:您正在使用的用戶

密碼:用戶密碼

grant_type:密碼

client_secret:11112222-3333-4444-5555-666666666666(如果客戶端“訪問類型”=“機密”,則需要客戶端密鑰)

很快:確保您的服務用戶分配了正確的角色來執行操作、登錄、查詢 keycloak(檢查文檔以獲取正確的查詢 url 和參數,總是具有挑戰性)


查看完整回答
反對 回復 2023-08-04
  • 3 回答
  • 0 關注
  • 268 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號