Apache Shiro 是一个强大且易用的 Java 安全框架,提供了身份验证、授权、加密和会话管理等功能。在 Shiro 中,Realm
是一个核心组件,负责从数据源(如数据库、LDAP、文件等)中获取安全数据(如用户、角色、权限等),并将其提供给 Shiro 框架进行身份验证和授权操作。本文将详细介绍如何在 Shiro 中使用 Realm
,包括自定义 Realm
的实现、配置以及常见的使用场景。
在 Shiro 中,Realm
是一个接口,定义了如何从数据源中获取安全数据。Shiro 提供了多个内置的 Realm
实现,如 IniRealm
、JdbcRealm
、TextConfigurationRealm
等,但通常情况下,我们需要根据实际需求自定义 Realm
。
Realm
的主要职责包括:
要自定义一个 Realm
,通常需要继承 AuthorizingRealm
类,并实现其中的 doGetAuthenticationInfo
和 doGetAuthorizationInfo
方法。
doGetAuthenticationInfo
方法doGetAuthenticationInfo
方法用于身份验证,通常是通过用户名和密码来验证用户的身份。以下是一个简单的实现示例:
import org.apache.shiro.authc.*; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; public class MyCustomRealm extends AuthorizingRealm { @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 将 token 转换为 UsernamePasswordToken UsernamePasswordToken upToken = (UsernamePasswordToken) token; // 获取用户名 String username = upToken.getUsername(); // 根据用户名从数据库或其他数据源中获取用户信息 User user = getUserByUsername(username); if (user == null) { throw new UnknownAccountException("用户不存在"); } // 返回 AuthenticationInfo 对象,包含用户名、密码和 Realm 名称 return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName()); } private User getUserByUsername(String username) { // 模拟从数据库中获取用户信息 if ("admin".equals(username)) { return new User("admin", "admin123"); } return null; } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 授权逻辑将在下一节中实现 return null; } }
doGetAuthorizationInfo
方法doGetAuthorizationInfo
方法用于获取用户的角色和权限信息。以下是一个简单的实现示例:
import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; public class MyCustomRealm extends AuthorizingRealm { @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 获取用户名 String username = (String) principals.getPrimaryPrincipal(); // 根据用户名获取用户的角色和权限信息 Set<String> roles = getRolesByUsername(username); Set<String> permissions = getPermissionsByUsername(username); // 创建 SimpleAuthorizationInfo 对象并设置角色和权限 SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.setRoles(roles); authorizationInfo.setStringPermissions(permissions); return authorizationInfo; } private Set<String> getRolesByUsername(String username) { // 模拟从数据库中获取用户角色信息 Set<String> roles = new HashSet<>(); if ("admin".equals(username)) { roles.add("admin"); } return roles; } private Set<String> getPermissionsByUsername(String username) { // 模拟从数据库中获取用户权限信息 Set<String> permissions = new HashSet<>(); if ("admin".equals(username)) { permissions.add("user:create"); permissions.add("user:delete"); } return permissions; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 身份验证逻辑已在上一节中实现 return null; } }
在 Shiro 中,Realm
的配置通常是通过 shiro.ini
文件或编程式配置来完成的。以下是两种常见的配置方式。
shiro.ini
配置文件在 shiro.ini
文件中,可以通过以下方式配置自定义的 Realm
:
[main] # 配置自定义的 Realm myRealm = com.example.MyCustomRealm # 配置 SecurityManager 使用的 Realm securityManager.realms = $myRealm
在 Java 代码中,可以通过编程式配置来设置 Realm
:
import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.realm.Realm; import org.apache.shiro.SecurityUtils; public class ShiroConfig { public static void main(String[] args) { // 创建自定义的 Realm Realm myRealm = new MyCustomRealm(); // 创建 SecurityManager 并设置 Realm DefaultSecurityManager securityManager = new DefaultSecurityManager(); securityManager.setRealm(myRealm); // 设置 SecurityManager SecurityUtils.setSecurityManager(securityManager); } }
配置好 Realm
后,就可以使用 Shiro 进行身份验证和授权操作了。以下是一个简单的示例:
import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; public class AuthenticationExample { public static void main(String[] args) { // 获取当前用户 Subject currentUser = SecurityUtils.getSubject(); // 创建用户名和密码的 Token UsernamePasswordToken token = new UsernamePasswordToken("admin", "admin123"); try { // 登录(身份验证) currentUser.login(token); System.out.println("登录成功"); } catch (AuthenticationException e) { System.out.println("登录失败: " + e.getMessage()); } } }
import org.apache.shiro.SecurityUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.subject.Subject; public class AuthorizationExample { public static void main(String[] args) { // 获取当前用户 Subject currentUser = SecurityUtils.getSubject(); // 检查用户是否具有某个权限 if (currentUser.isPermitted("user:create")) { System.out.println("用户具有创建用户的权限"); } else { System.out.println("用户没有创建用户的权限"); } // 检查用户是否具有某个角色 if (currentUser.hasRole("admin")) { System.out.println("用户是管理员"); } else { System.out.println("用户不是管理员"); } } }
在实际应用中,用户的密码通常需要进行加密存储。Shiro 提供了 CredentialsMatcher
接口来处理密码的匹配。可以通过配置 HashedCredentialsMatcher
来实现密码的加密和验证。
import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.crypto.hash.Sha256Hash; public class MyCustomRealm extends AuthorizingRealm { public MyCustomRealm() { // 配置 HashedCredentialsMatcher HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); credentialsMatcher.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME); credentialsMatcher.setHashIterations(1024); setCredentialsMatcher(credentialsMatcher); } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 身份验证逻辑 return null; } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 授权逻辑 return null; } }
在某些情况下,可能需要使用多个 Realm
来处理不同的数据源。Shiro 提供了 ModularRealmAuthenticator
来支持多个 Realm
的配置。
[main] # 配置多个 Realm realm1 = com.example.Realm1 realm2 = com.example.Realm2 # 配置 SecurityManager 使用的 Realm securityManager.realms = $realm1, $realm2
为了提高性能,Shiro 提供了缓存机制来缓存 Realm
的授权信息。可以通过配置 CacheManager
来启用缓存。
[main] # 配置缓存管理器 cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager securityManager.cacheManager = $cacheManager # 配置 Realm 使用缓存 myRealm = com.example.MyCustomRealm myRealm.cachingEnabled = true securityManager.realms = $myRealm
Realm
是 Shiro 中非常重要的组件,负责从数据源中获取安全数据,并提供给 Shiro 进行身份验证和授权操作。通过自定义 Realm
,我们可以灵活地集成不同的数据源,并根据实际需求实现复杂的权限控制逻辑。本文详细介绍了如何自定义 Realm
、配置 Realm
以及使用 Realm
进行身份验证和授权,希望能帮助读者更好地理解和使用 Shiro 中的 Realm
。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。