Apache Shiro 使用教程
Apache Shiro是一个强大且灵活的开源安全框架,主要用于处理身份验证(Authentication)、授权(Authorization)、加密(Cryptography)和会话管理(Session Management)等安全相关的任务。它简化了在Java应用程序中集成安全功能的复杂性,广泛适用于各种类型的项目,如Web应用、命令行工具等。本教程将深入介绍Shiro的各个核心概念和功能,并通过一个基于Spring Boot的示例项目展示如何在项目中实际使用Shiro。
一、Shiro 核心概念
1.1 Subject
Subject
是Shiro的核心概念,它代表一个实体,可以是用户、服务或其他任何需要与安全系统交互的主体。通过Subject
,开发者可以执行认证、授权、会话管理等操作。例如,当用户登录系统时,实际上是通过Subject
进行身份验证;当需要检查用户是否有权限执行某个操作时,也是通过Subject
进行授权判断。
1.2 SecurityManager
SecurityManager
是Shiro的安全管理中心,负责协调和管理所有的安全操作。它就像是一个大脑,接收来自Subject
的请求(如登录、权限检查等),并委派相应的Realm
去获取和处理安全数据。在一个应用程序中,通常只需要一个SecurityManager
实例,它是整个Shiro安全体系的核心。
1.3 Realm
Realm
是Shiro用于获取安全数据的组件,它定义了数据源的来源,比如数据库、LDAP(轻量级目录访问协议)、内存等。Realm
负责从特定的数据源中读取用户信息、角色信息和权限信息等,以支持SecurityManager
进行认证和授权操作。开发者需要根据实际需求实现自定义的Realm
或者使用Shiro提供的默认Realm
。
二、Shiro 的核心功能
2.1 身份验证(Authentication)
身份验证是确认用户身份的过程,通常通过用户名和密码或其他凭证来完成。Shiro提供了简单的接口和方法,让开发者可以方便地实现身份验证逻辑。当用户提交登录请求时,Subject
会调用login
方法进行身份验证,SecurityManager
会将验证请求委派给配置的Realm
,Realm
根据用户提供的凭证在数据源中查找匹配的用户信息,如果找到且凭证验证通过,则身份验证成功;否则,抛出身份验证异常。
2.2 授权(Authorization)
授权是确定用户是否有权限访问特定资源或执行某个操作的过程。Shiro通过角色和权限的概念来实现授权管理。开发者可以为用户分配角色,为角色分配权限,然后在代码中通过Subject
的isPermitted
或hasRole
方法来检查用户是否具有相应的权限或角色。例如,在一个文件管理系统中,只有具有“管理员”角色的用户才有权删除文件,Shiro就可以通过授权机制来确保只有授权用户可以执行此操作。
2.3 加密(Cryptography)
Shiro提供了多种加密算法和工具,用于保护敏感信息,如用户密码的存储和加密传输等。例如,可以使用HashedCredentialsMatcher
来对用户密码进行哈希加密存储,防止密码泄露后被直接获取。Shiro还支持对称加密和非对称加密算法,满足不同场景下的加密需求。
2.4 会话管理(Session Management)
Shiro提供了会话管理功能,用于跟踪和管理用户的会话状态。在一个Web应用中,用户的会话状态可以包含用户的登录状态、登录时间、最近访问的页面等信息。Shiro的会话管理机制允许开发者在不同的应用服务器和分布式环境中轻松地管理用户会话,并且提供了会话监听器、会话过期处理等功能,方便开发者进行定制和扩展。
三、基于Spring Boot集成Shiro的示例
3.1 创建Spring Boot项目
首先,创建一个基于Spring Boot的Web应用项目。可以使用Spring Initializr(https://start.spring.io/ )工具快速创建项目,选择以下依赖:
• Spring Web
• Spring Boot DevTools(可选,用于开发时的热部署和快速重启)
3.2 添加Shiro依赖
在项目的pom.xml
文件中添加Shiro和Shiro与Spring集成的依赖:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.9.1</version>
</dependency>
3.3 配置Shiro
创建一个配置类ShiroConfig
,用于配置Shiro的核心组件,包括SecurityManager
、Realm
和过滤器链等:
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ShiroConfig {
@Bean
public Realm realm() {
// 这里可以创建自定义Realm或使用Shiro提供的默认Realm
return new CustomRealm();
}
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(realm());
return manager;
}
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
// 配置路径的访问权限,anon表示无需认证,authc表示需要认证
chainDefinition.addPathDefinition("/login", "anon");
chainDefinition.addPathDefinition("/logout", "logout");
chainDefinition.addPathDefinition("/**", "authc");
return chainDefinition;
}
}
3.4 自定义Realm
创建一个自定义的Realm
类CustomRealm
,用于从数据库或其他数据源中获取用户信息和权限信息:
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 {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername();
// 模拟从数据库中获取用户信息
if (!"admin".equals(username) &&!"user".equals(username)) {
throw new UnknownAccountException("用户不存在");
}
String password = "123456"; // 实际应用中应从数据库获取真实的用户密码
return new SimpleAuthenticationInfo(username, password, getName());
}
// 用户授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 模拟从数据库中获取用户角色和权限
if ("admin".equals(username)) {
authorizationInfo.addRole("admin");
authorizationInfo.addStringPermission("user:delete");
} else if ("user".equals(username)) {
authorizationInfo.addRole("user");
authorizationInfo.addStringPermission("user:view");
}
return authorizationInfo;
}
}
3.5 编写控制器
创建一个控制器类ShiroController
,用于处理登录、访问受保护资源等请求:
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ShiroController {
@GetMapping("/login")
public String loginPage() {
return "登录页面";
}
@PostMapping("/login")
public String login(@RequestParam String username, @RequestParam String password) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
subject.login(token);
return "登录成功";
} catch (AuthenticationException e) {
return "登录失败: " + e.getMessage();
}
}
@GetMapping("/logout")
public String logout() {
SecurityUtils.getSubject().logout();
return "已登出";
}
@GetMapping("/protected")
public String protectedResource() {
Subject subject = SecurityUtils.getSubject();
if (subject.isAuthenticated()) {
return "访问受保护资源成功";
} else {
return "请先登录";
}
}
}
3.6 测试应用
启动Spring Boot应用程序,访问http://localhost:8080/login
,可以看到登录页面。通过表单或发送POST请求(http://localhost:8080/login?username=admin&password=123456
)进行登录。登录成功后,可以访问受保护的资源http://localhost:8080/protected
,如果未登录则会被拦截并重定向到登录页面。同时,可以访问http://localhost:8080/logout
来登出当前用户。
四、总结
本教程介绍了Apache Shiro的核心概念和主要功能,包括身份验证、授权、加密和会话管理。通过一个基于Spring Boot的示例项目,展示了如何配置和使用Shiro来实现简单的安全控制。在实际项目中,你可以根据需求进一步扩展和定制Shiro的功能,如集成数据库、实现更复杂的权限管理逻辑等。Shiro作为一个成熟且强大的安全框架,能够大大简化Java应用程序中的安全开发工作,提高应用程序的安全性和可靠性。