Keycload + Spring boot: Bắt đầu với Keycload và Spring boot – Bắt đầu làm việc với User trong Realm

Note: Chuỗi bài viết chủ yếu mang tính lưu trữ kiến thức cho bản thân và chia sẻ lại cho các bạn. Vì khi mình bắt đầu làm việc với Keycload thì rất khó tìm các hướng dẫn bằng tiếng việt. Bài viết có tham khảo từ nhiều nguồn khác nhau. Thanks ! 1. Keycload

Note: Chuỗi bài viết chủ yếu mang tính lưu trữ kiến thức cho bản thân và chia sẻ lại cho các bạn. Vì khi mình bắt đầu làm việc với Keycload thì rất khó tìm các hướng dẫn bằng tiếng việt. Bài viết có tham khảo từ nhiều nguồn khác nhau. Thanks !

1. Keycload là gì?

Cơ bản Keycloak là một Open Source Identity và Access Management cho Modern Applications và Services. Dùng để quản lý nhận dạng và truy cập vào các ứng dụng/ dịch vụ.

Về hướng dẫn cài đặt, cách thêm realm, client, role, user trên giao diện web của Keycloak thì các bạn có thể check google hoặc tại đây: Link1 hoặc tại đây: Link2 ( Các bạn ấy viết rất đầy đủ và chi tiết về các thông số hiển thị trên giao diện của Keycload)

2. Vậy đã có hướng dẫn rồi thì mình viết về vấn đề gì?

Nếu một ngày đẹp trời, bạn cho phép một người ( đơn vị) thứ 3 nhảy vào thao tác với ứng dụng Keycload của bạn nhưng lại không muốn cho họ có quyền vào thẳng ứng dụng của bạn để thực hiện…. Chà. Vậy bạn cần 1 ứng dụng/APIs cho họ gọi để thao tác với Keycload.
Vậy bạn cần tương tác với Keycload từ code chứ không phải từ giao diện.

3. Nếu đây là vấn đề bạn quan tâm => vậy bắt đầu thôi!

Để bắt đầu, Mình khuyên các bạn nên đọc qua hai bài viết mình đã giới thiệu và tạo được realm, client, role và 1 user cho client.

Chú ý!!!!! Mình đã mất nửa ngày cho vấn đề đơn giản này => Đó là Role Mapping của user

Như ảnh bên dưới, 1 user có 2 kiểu role Realm RolesClient RolesRealm Roles : Các bạn sẽ tạo được khi tạo xong Realm
Client Roles: Đây là vấn đề chính. Để user có quyền thao tác và call API của Keycload các bạn phải set client role cho user đó, có rất nhiều loại quyền, các bạn có thể đọc chi tiết.

Ở bài demo này mình sẽ sử dụng quyền realm-management và Available Roles là realm-admin

3.1 Dependency

Để sử dụng Keycload trong Spring boot thì các bạn cần:

  1. Đương nhiên 1 ứng dụng spring cơ bản rồi, Gradle hay Maven đều được
  2. Dependency của Keycload

Với Gradle các bạn thêm vào file build.gradle

	implementation group: 'org.keycloak', name: 'keycloak-spring-boot-starter', version: '16.1.0'
	implementation group: 'org.keycloak', name: 'keycloak-admin-client', version: '16.1.0'

Với Maven thì các bạn thêm vào file pom

<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-spring-boot-starter</artifactId>
    <version>16.1.0</version>
</dependency>
<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-admin-client</artifactId>
    <version>16.1.0</version>
</dependency>

3.2 Tạo Keycload Instance

Mình sẽ viết 1 hàm để lấy ra instance của keycload. ***env*** là biến môi trường để lấy ra dữ liệu đã lưu trong file .properties hoặc .yaml ( Dùng Spring thì 100% các bạn thừa biết rồi , cứ vẽ vời thêm chuyện!!!!)

Hàm để lấy ra instance có dạng này Keycloak.getInstance(serverUlr, realm, username, password, clientId, clientSecret)

Các bạn nên viết 1 file utils như này

    @Autowired
    Environment env;
    
    public Keycloak getKeycloakInstance() {
        return Keycloak.getInstance(
                env.getProperty("keycloak.auth-server-url"),
                env.getProperty("keycloak.realm"),
                env.getProperty("keycloak-config.username"),
                env.getProperty("keycloak-config.password"),
                env.getProperty("keycloak.resource"),
                env.getProperty("keycloak-config.client-secret"));
    }

Sau đó các bạn cần dùng ở đâu thì gọi ra thôi

 @Autowired
    KeycloakUtils keycloakUtils;

    public void getListUser(UserRegisterRequest request) {

        Keycloak keycloak = keycloakUtils.getKeycloakInstance();
        .....

3.2 Lấy token ( nếu cần)

Token phục vụ api login

keycloak.tokenManager().getAccessToken().getToken();
keycloak.tokenManager().getAccessToken().getExpiresIn();

3.3 Lấy danh sách users

Lưu ý: các bạn chỉ có thể lấy ra danh sách user của client mà user admin đã dùng để lấy Keycloak instance thôi nhé!!!!

 try {
        keycloak = getKeycloakInstance();
        List<UserRepresentation>   userRepresentations = keycloak.realm(env.getProperty("keycloak.realm")).users().list();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (keycloak != null) {
                keycloak.close();
            }
        }

Quá đơn giản đúng không, các bạn nhớ phải gọi keycloak.close(); để đóng instance sau khi call xong nhé

3.4 Lấy user

Thường thì 1 user sẽ có thể định danh bởi 2 trường, userIduserName

Nếu lấy theo userName:

keycloak = getKeycloakInstance();
res = keycloak.realm(env.getProperty("keycloak.realm")).users().search(request.getParam()).get(0);

Nếu lấy theo userId: các bạn không thể truyền vào id để get trực tiếp như user được, nên ở đây mình lọc ra từ danh sách user luôn ( hơi bị củ chuối):

           UserRepresentation user = new UserRepresentation();
           keycloak = getKeycloakInstance();
           List<UserRepresentation> userRepresentations = keycloak.realm(env.getProperty("keycloak.realm")).users().list();
            for (UserRepresentation lts : userRepresentations) {
                if (lts.getId().equalsIgnoreCase(request.getParam())) {
                    user = lts;
                    break;
                }
            }

3.5 Add User

Để thêm mới một user các bạn làm như sau:

Các bạn cần có 1 model AddUserDTO như sau ( mình xài Lombok nên không có Get/Set j cả nha):

public class AddUserDTO  {
    private String userName;
    private String email;
    private String phoneNumber;
    private String password;
    private String firstname;
    private String lastName;
}

Như các bạn thấy mình có 1 biến statusCode ở cuối cùng, Keycload sẽ trả về status theo chuẩn HTTP để chúng ta dễ hanlling nhé

            keycloak = getKeycloakInstance();
            UsersResource userResource = keycloak.realm(env.getProperty("keycloak.realm")).users();
            CredentialRepresentation credential = Credentials
                    .createPasswordCredentials(request.getPassword());
            UserRepresentation user = new UserRepresentation();
            user.setUsername(request.getUserName());
            user.setFirstName(request.getFirstname());
            user.setLastName(request.getLastName());
            user.setEmail(request.getEmail());
            user.setCredentials(Collections.singletonList(credential));
            user.setEnabled(true);
            Response res = userResource.create(user);
            int statusCode = res.getStatus();
            

3.6 Update User

Để update một user các bạn làm như sau:

Cần Model UpdateUserDTO như sau:

public class UpdateUserDTO  {
   private String userId;
    private String userName;
    private String email;
    private String phoneNumber;
    private String password;
    private String firstname;
    private String lastName;
}

Làm thôi

                UsersResource userResource = keycloak.realm(env.getProperty("keycloak.realm")).users();
                CredentialRepresentation credential = Credentials
                        .createPasswordCredentials(request.getPassword());
                UserRepresentation user = new UserRepresentation();
                user.setUsername(request.getUserName());
                user.setFirstName(request.getFirstname());
                user.setLastName(request.getLastName());
                user.setEmail(request.getEmail());
                user.setCredentials(Collections.singletonList(credential));
                 userResource.get(request.getUserId()).update(user);

3.7 Remove User

           UsersResource userResource = keycloak.realm(env.getProperty("keycloak.realm")).users();
            UserRepresentation user = new UserRepresentation();
            userResource.get(userId).remove();

4 Các thao tác quan trọng khác

Khi thao tác với user không chỉ CRUD là đủ, các bạn cần set quyền hạn ( Role), set trạng thái ( enable/disable), thêm các attribute cho user

Mình sẽ hướng dẫn về trạng thái và attribute, còn role sẽ để bài sau nhé:

Trạng thái của user

Data của khách hàng là cực kì quan trọng, do đó trên thực tế việc remove ít khi được thực hiện, thay vào đó người ta thường chuyển trạng thái hoạt động về disable

Cho nên các bạn chỉ cần set trạng thái của user về disable là user đó sẽ không thể đăng nhập hệ thống được nữa:

 user.setEnabled(false);

Attribute của user

Trên thực tế các thông tin khi tạo mới user bao gồm fistName, lastName, email là không đủ. Các bạn cần thêm một số trường như SĐT, Địa chỉ…….

Vậy các bạn làm như sau (:

Ở bước thêm mới:

//tạo mới mapp Attribute
  Map<String, List<String>> attribute = new HashMap<>();
  //tạo các attribute
  List<String> phone = Arrays.asList(request.getPhoneNumber());
  List<String> mobileDevice = Arrays.asList(request.getMobileDevice());
  
  //đẩy vào Map
  attribute.put(Constants.PHONE_NUMBER, phone);
  attribute.put(Constants.DEVICE, device);
  attribute.put(Constants.MOBILE_DEVICE, mobileDevice);
  
  //set att
  user.setAttributes(attribute);
  

Ở bước Update các bạn cần lấy ra attribute cũ và cập nhật lại giá trị cần xử lý thôi nhé, làm như bước tạo mới là nó clear cả dữ liệu không cần update đó

Note: Kiểu dữ liệu của attribute là varchar(255) 😃 nên các bạn muốn lưu j dài hơn nhớ thay đổi trong db của Keycload nhé

5 Tóm tắt bài viết

Bài viết này mình hướng dẫn các bạn tạo user và các thao tác với user của Kecload thông qua Spring boot. Hi vọng có thể giúp đỡ được các bạn trong quá trình làm việc.

Có sai sót ở đâu các bạn giúp đỡ mình nhé

Tham khảo:

https://huongdanjava.com/vi/keycloak
https://www.baeldung.com/spring-boot-keycloak
https://medium.com/teamarimac/how-to-secure-spring-boot-application-with-keycloak-3ffed7e500a4

Nguồn: viblo.asia

Bài viết liên quan

Thay đổi Package Name của Android Studio dể dàng với plugin APR

Nếu bạn đang gặp khó khăn hoặc bế tắc trong việc thay đổi package name trong And

Lỗi không Update Meta_Value Khi thay thế hình ảnh cũ bằng hình ảnh mới trong WordPress

Mã dưới đây hoạt động tốt có 1 lỗi không update được postmeta ” meta_key=

Bài 1 – React Native DevOps các khái niệm và các cài đặt căn bản

Hướng dẫn setup jenkins agent để bắt đầu build mobile bằng jenkins cho devloper an t

Chuyển đổi từ monolith sang microservices qua ví dụ

1. Why microservices? Microservices là kiến trúc hệ thống phần mềm hướng dịch vụ,