您好,登录后才能下订单哦!
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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。