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ôngFirstSuccessfulStrategy: Chỉ sử dụng kết quả đầu tiên thành côngAllSuccessfulStrategy: 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