溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Shiro Realm權限認證怎么實現

發布時間:2021-12-27 16:43:17 來源:億速云 閱讀:194 作者:iii 欄目:大數據

Shiro Realm權限認證怎么實現

Apache Shiro 是一個強大且易用的 Java 安全框架,提供了認證、授權、加密和會話管理等功能。在 Shiro 中,Realm 是一個核心組件,用于連接應用程序的安全數據(如用戶、角色、權限等)與 Shiro 的安全框架。本文將詳細介紹如何在 Shiro 中實現 Realm 權限認證。

1. Shiro 簡介

1.1 Shiro 的核心概念

  • Subject: 當前與系統交互的用戶或程序。
  • SecurityManager: Shiro 的核心,管理所有 Subject 的安全操作。
  • Realm: 連接 Shiro 與應用程序的安全數據源,負責認證和授權。

1.2 Shiro 的工作流程

  1. 應用程序通過 Subject 與 Shiro 交互。
  2. SecurityManager 負責管理所有 Subject 的安全操作。
  3. Realm 負責從數據源中獲取安全數據(如用戶、角色、權限等),并進行認證和授權。

2. Realm 的作用

Realm 是 Shiro 與應用程序安全數據之間的橋梁。它負責:

  • 認證(Authentication): 驗證用戶的身份。
  • 授權(Authorization): 驗證用戶是否有權限執行某個操作。

3. 實現自定義 Realm

3.1 創建自定義 Realm

要實現自定義 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;
    }
}

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 數據庫表設計

假設我們有以下三張表:

  • 用戶表(user): 存儲用戶信息。
  • 角色表(role): 存儲角色信息。
  • 權限表(permission): 存儲權限信息。
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 權限認證,并在實際項目中應用這些知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女