您好,登录后才能下订单哦!
Apache Shiro 是一个强大且易用的 Java 安全框架,提供了认证、授权、加密和会话管理等功能。在 Shiro 中,Realm 是一个核心组件,用于连接应用程序的安全数据(如用户、角色、权限等)与 Shiro 的安全框架。本文将详细介绍如何在 Shiro 中实现 Realm 权限认证。
Subject 与 Shiro 交互。SecurityManager 负责管理所有 Subject 的安全操作。Realm 负责从数据源中获取安全数据(如用户、角色、权限等),并进行认证和授权。Realm 是 Shiro 与应用程序安全数据之间的桥梁。它负责:
要实现自定义 Realm,需要继承 AuthorizingRealm 类,并实现以下两个方法:
doGetAuthenticationInfo: 用于认证。doGetAuthorizationInfo: 用于授权。import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import java.util.HashSet;
import java.util.Set;
public class CustomRealm extends AuthorizingRealm {
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 获取用户名
        String username = (String) token.getPrincipal();
        // 根据用户名从数据库或其他数据源中获取用户信息
        User user = getUserByUsername(username);
        if (user == null) {
            throw new UnknownAccountException("用户不存在");
        }
        // 返回认证信息
        return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());
    }
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // 获取用户名
        String username = (String) principals.getPrimaryPrincipal();
        // 根据用户名从数据库或其他数据源中获取用户的角色和权限
        Set<String> roles = getRolesByUsername(username);
        Set<String> permissions = getPermissionsByUsername(username);
        // 返回授权信息
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(roles);
        authorizationInfo.setStringPermissions(permissions);
        return authorizationInfo;
    }
    // 模拟从数据库获取用户信息
    private User getUserByUsername(String username) {
        // 这里应该是从数据库或其他数据源中获取用户信息
        // 这里为了演示,直接返回一个模拟的用户
        if ("admin".equals(username)) {
            return new User("admin", "123456");
        }
        return null;
    }
    // 模拟从数据库获取用户角色
    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;
    }
}
在 Shiro 的配置文件中,需要将自定义的 Realm 配置到 SecurityManager 中。
[main]
customRealm = com.example.CustomRealm
securityManager.realms = $customRealm
在应用程序中,可以通过 Subject 进行认证和授权操作。
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
public class ShiroExample {
    public static void main(String[] args) {
        // 获取当前用户
        Subject currentUser = SecurityUtils.getSubject();
        // 创建认证令牌
        UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
        try {
            // 登录认证
            currentUser.login(token);
            System.out.println("认证成功");
            // 检查角色
            if (currentUser.hasRole("admin")) {
                System.out.println("用户拥有 admin 角色");
            }
            // 检查权限
            if (currentUser.isPermitted("user:create")) {
                System.out.println("用户拥有 user:create 权限");
            }
        } catch (AuthenticationException e) {
            System.out.println("认证失败: " + e.getMessage());
        } finally {
            // 退出登录
            currentUser.logout();
        }
    }
}
在实际应用中,用户、角色和权限信息通常存储在数据库中。我们可以通过集成数据库来实现 Realm 的认证和授权。
假设我们有以下三张表:
CREATE TABLE user (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL,
    password VARCHAR(50) NOT NULL
);
CREATE TABLE role (
    id INT PRIMARY KEY AUTO_INCREMENT,
    role_name VARCHAR(50) NOT NULL
);
CREATE TABLE permission (
    id INT PRIMARY KEY AUTO_INCREMENT,
    permission_name VARCHAR(50) NOT NULL
);
CREATE TABLE user_role (
    user_id INT,
    role_id INT,
    PRIMARY KEY (user_id, role_id)
);
CREATE TABLE role_permission (
    role_id INT,
    permission_id INT,
    PRIMARY KEY (role_id, permission_id)
);
在自定义 Realm 中,我们可以通过 JDBC 或 ORM 框架(如 MyBatis、Hibernate)从数据库中获取用户、角色和权限信息。
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashSet;
import java.util.Set;
public class CustomRealm extends AuthorizingRealm {
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        try (Connection conn = getConnection()) {
            PreparedStatement ps = conn.prepareStatement("SELECT password FROM user WHERE username = ?");
            ps.setString(1, username);
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                String password = rs.getString("password");
                return new SimpleAuthenticationInfo(username, password, getName());
            } else {
                throw new UnknownAccountException("用户不存在");
            }
        } catch (Exception e) {
            throw new AuthenticationException("数据库连接失败", e);
        }
    }
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String) principals.getPrimaryPrincipal();
        Set<String> roles = new HashSet<>();
        Set<String> permissions = new HashSet<>();
        try (Connection conn = getConnection()) {
            // 获取用户角色
            PreparedStatement ps = conn.prepareStatement(
                "SELECT r.role_name FROM role r JOIN user_role ur ON r.id = ur.role_id JOIN user u ON ur.user_id = u.id WHERE u.username = ?");
            ps.setString(1, username);
            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
                roles.add(rs.getString("role_name"));
            }
            // 获取用户权限
            ps = conn.prepareStatement(
                "SELECT p.permission_name FROM permission p JOIN role_permission rp ON p.id = rp.permission_id JOIN role r ON rp.role_id = r.id JOIN user_role ur ON r.id = ur.role_id JOIN user u ON ur.user_id = u.id WHERE u.username = ?");
            ps.setString(1, username);
            rs = ps.executeQuery();
            while (rs.next()) {
                permissions.add(rs.getString("permission_name"));
            }
        } catch (Exception e) {
            throw new AuthorizationException("数据库连接失败", e);
        }
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(roles);
        authorizationInfo.setStringPermissions(permissions);
        return authorizationInfo;
    }
    private Connection getConnection() throws Exception {
        // 这里应该是从数据库连接池中获取连接
        // 这里为了演示,直接返回一个连接
        return DriverManager.getConnection("jdbc:mysql://localhost:3306/shiro", "root", "password");
    }
}
通过实现自定义 Realm,我们可以将 Shiro 与应用程序的安全数据源(如数据库)连接起来,实现灵活的认证和授权功能。在实际应用中,我们可以根据需求扩展 Realm,集成更多的安全数据源,并优化性能。
Shiro 提供了丰富的 API 和灵活的扩展机制,使得开发者可以轻松地实现复杂的权限管理需求。通过本文的介绍,希望读者能够掌握如何在 Shiro 中实现 Realm 权限认证,并在实际项目中应用这些知识。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。