Shiro Realm权限认证怎么实现

发布时间:2021-12-27 16:43:17 作者:iii
来源:亿速云 阅读:166

Shiro Realm权限认证怎么实现

Apache Shiro 是一个强大且易用的 Java 安全框架,提供了认证、授权、加密和会话管理等功能。在 Shiro 中,Realm 是一个核心组件,用于连接应用程序的安全数据(如用户、角色、权限等)与 Shiro 的安全框架。本文将详细介绍如何在 Shiro 中实现 Realm 权限认证。

1. Shiro 简介

1.1 Shiro 的核心概念

1.2 Shiro 的工作流程

  1. 应用程序通过 Subject 与 Shiro 交互。
  2. SecurityManager 负责管理所有 Subject 的安全操作。
  3. Realm 负责从数据源中获取安全数据(如用户、角色、权限等),并进行认证和授权。

2. Realm 的作用

Realm 是 Shiro 与应用程序安全数据之间的桥梁。它负责:

3. 实现自定义 Realm

3.1 创建自定义 Realm

要实现自定义 Realm,需要继承 AuthorizingRealm 类,并实现以下两个方法:

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;
    }
}

3.2 配置 Realm

在 Shiro 的配置文件中,需要将自定义的 Realm 配置到 SecurityManager 中。

[main]
customRealm = com.example.CustomRealm
securityManager.realms = $customRealm

3.3 使用 Realm 进行认证和授权

在应用程序中,可以通过 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();
        }
    }
}

4. 集成数据库

在实际应用中,用户、角色和权限信息通常存储在数据库中。我们可以通过集成数据库来实现 Realm 的认证和授权。

4.1 数据库表设计

假设我们有以下三张表:

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)
);

4.2 修改自定义 Realm

在自定义 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");
    }
}

5. 总结

通过实现自定义 Realm,我们可以将 Shiro 与应用程序的安全数据源(如数据库)连接起来,实现灵活的认证和授权功能。在实际应用中,我们可以根据需求扩展 Realm,集成更多的安全数据源,并优化性能。

Shiro 提供了丰富的 API 和灵活的扩展机制,使得开发者可以轻松地实现复杂的权限管理需求。通过本文的介绍,希望读者能够掌握如何在 Shiro 中实现 Realm 权限认证,并在实际项目中应用这些知识。

推荐阅读:
  1. shiro教程(4)-shiro与项目集成开发
  2. shiro教程(2)- shiro介绍

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

shiro realm

上一篇:虚拟机联网方式有哪些

下一篇:大数据中免费的探索性数据分析工具有哪些

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》