Xác thực danh tính trong Shiro - Realm

1. Khái niệm Realm

Realm là nơi lưu trữ dữ liệu an ninh (người dùng, vai trò, quyền hạn).

Để xác thực danh tính, SecurityManager cần truy xuất dữ liệu từ Realm để kiểm tra thông tin đăng nhập, đồng thời lấy thông tin vai trò/quyền để kiểm soát thao tác người dùng.

2. Triển khai Realm tùy chỉnh

package com.example.shiro;

import java.util.HashSet;
import java.util.Set;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 * Lớp Realm tùy chỉnh
 */
public class CustomRealm extends AuthorizingRealm {

    /**
     * Xử lý thông tin phân quyền
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        
        String username = (String) getAvailablePrincipal(principals);
        
        // Lấy danh sách quyền từ nguồn dữ liệu
        Set<String> permissions = new HashSet<>();
        permissions.add("view_data");
        permissions.add("edit_content");
        info.setStringPermissions(permissions);
        
        // Gán vai trò cho người dùng
        Set<String> roles = new HashSet<>();
        roles.add("admin");
        roles.add("editor");
        info.setRoles(roles);
        
        return info;
    }

    /**
     * Xử lý xác thực tài khoản
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        String username = upToken.getUsername();
        
        // Kiểm tra thông tin đăng nhập
        if (!"admin".equals(username)) {
            throw new AuthenticationException("Tên đăng nhập không hợp lệ");
        }
        
        // Trả về thông tin xác thực
        return new SimpleAuthenticationInfo(username, "password123".toCharArray(), getName());
    }
}

3. Cấu hình nhiều Realm trong xác thực

3.1. Tạo 2 Realm tùy chỉnh

  • Realm1: Xử lý xác thực chính
  • Realm2: Thử nghiệm lỗi xác thực
// Trong phương thức xác thực của Realm2
if ("testuser".equals(username)) {
    throw new AuthenticationException("Lỗi xác thực từ Realm2");
}

3.2. Cấu hình trong tệp shiro.ini

[main]
# Định nghĩa các Realm
realmOne = com.example.shiro.CustomRealm1
realmTwo = com.example.shiro.CustomRealm2

# Cấu hình authenticator
authManager = org.apache.shiro.authc.pam.ModularRealmAuthenticator
strategyPolicy = org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy

# Áp dụng chiến lược xác thực
authManager.authenticationStrategy = $strategyPolicy
authManager.realms = $realmOne, $realmTwo

# Gán authenticator cho securityManager
securityManager.authenticator = $authManager

4. Chiến lược xác thực đa Realm

4.1. Các loại chiến lược mặc định

  • AtLeastOneSuccessfulStrategy: Ít nhất 1 Realm thành công thì cả hệ thống thành công
  • FirstSuccessfulStrategy: Chỉ sử dụng kết quả đầu tiên thành công
  • AllSuccessfulStrategy: Tất cả Realm phải thành công

4.2. Tùy chỉnh chiến lược xác thực

package com.example.shiro;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.pam.AbstractAuthenticationStrategy;
import org.apache.shiro.realm.Realm;

/**
 * Chiến lược xác thực tùy chỉnh
 */
public class CustomAuthStrategy extends AbstractAuthenticationStrategy {

    @Override
    public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, 
                                          AuthenticationInfo singleResult, 
                                          AuthenticationInfo aggregateResult, 
                                          Throwable t) throws AuthenticationException {
        
        // Kiểm tra điều kiện đặc biệt cho Realm cụ thể
        if ("specialRealm".equals(realm.getName()) && singleResult == null) {
            throw new AuthenticationException("Yêu cầu xác thực từ realm đặc biệt thất bại");
        }
        
        return super.afterAttempt(realm, token, singleResult, aggregateResult, t);
    }
}

4.3. Áp dụng chiến lược mới

[main]
customStrategy = com.example.shiro.CustomAuthStrategy
authManager.authenticationStrategy = $customStrategy

5. Thứ tự xử lý các Realm

5.1. Chỉ định thứ tự rõ ràng

authManager.realms = $realmOne, $realmTwo

5.2. Thứ tự mặc định

  • Realm được khai báo trước sẽ được xử lý trước

Các loại thông tin có thể lưu trữ:

  • Realm1: Tài khoản/email + mật khẩu
  • Realm2: Số điện thoại + mã OTP
  • Realm3: Mã QR + sinh trắc học

Thẻ: shiro Realm Xác thực Java Shiro Security

Đăng vào ngày 4 tháng 6 lúc 23:21