以下是一个Shiro学习教程:
一、Shiro简介
Apache Shiro是一个强大且易用的Java安全框架,它提供了身份验证、授权、加密和会话管理等功能。Shiro的设计理念是简单易用,同时又能满足复杂的安全需求,可以轻松地集成到各种Java应用程序中,如Web应用、命令行应用、移动应用等。
二、环境搭建
1. 项目创建与依赖引入
- 如果你使用Maven构建项目,在
pom.xml
文件中添加Shiro依赖:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.7.1</version>
</dependency>
- 如果是Gradle项目,在
build.gradle
文件中添加:
implementation 'org.apache.shiro:shiro-core:1.7.1'
三、核心概念
1. 主体(Subject)
- 主体可以是任何与应用交互的实体,如用户、第三方服务或定时任务等。在Web应用中,通常代表当前用户。可以通过以下方式获取Subject实例:
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
Subject subject = SecurityUtils.getSubject();
2. 身份验证(Authentication)
- 验证主体身份的过程。
简单示例
- 首先定义用户的账号和密码信息(在实际应用中,这些信息通常存储在数据库中):
import org.apache.shiro.authc.UsernamePasswordToken;
// 假设用户名为 "user",密码为 "password"
UsernamePasswordToken token = new UsernamePasswordToken("user", "password");
- 然后进行身份验证:
try {
subject.login(token);
System.out.println("身份验证成功");
} catch (org.apache.shiro.authc.AuthenticationException e) {
System.out.println("身份验证失败: " + e.getMessage());
}
3. 授权(Authorization)
- 确定主体是否有权访问特定资源或执行特定操作的过程。
基于角色的授权示例
- 假设已经完成身份验证,在Shiro中配置角色信息(在实际应用中,角色信息也可能从数据库获取)。
- 定义一个简单的权限检查:
if (subject.hasRole("admin")) {
System.out.println("该用户具有管理员权限");
} else {
System.out.println("该用户不是管理员");
}
基于权限的授权示例
- 除了角色,还可以基于权限进行更细粒度的授权。
if (subject.isPermitted("user:create")) {
System.out.println("该用户具有创建用户的权限");
} else {
System.out.println("该用户没有创建用户的权限");
}
4. 会话(Session)
- Shiro提供了自己的会话管理功能。
会话创建与使用示例
// 获取会话对象
import org.apache.shiro.session.Session;
Session session = subject.getSession();
// 在会话中存储数据
session.setAttribute("key", "value");
// 从会话中获取数据
Object value = session.getAttribute("key");
四、Shiro在Web应用中的集成
1. 配置ShiroFilter
- 在Web应用中,通常需要配置ShiroFilter来拦截请求并进行安全处理。
- 如果使用Spring Boot集成Shiro,首先创建一个Shiro配置类:
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> filterChainDefinitionMap = new HashMap<>();
// 配置哪些URL需要认证,哪些不需要
filterChainDefinitionMap.put("/public/**", "anon");
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 这里可以设置自定义的Realm,用于从数据库等获取用户信息
return securityManager;
}
}
2. Realm(领域)
- Realm是Shiro获取安全数据(如用户、角色、权限)的组件。
自定义Realm示例
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
public class MyRealm extends AuthorizingRealm {
// 用于身份验证
@Override
protected AuthenticationInfo doAuthenticate(AuthenticationToken token) throws AuthenticationException {
// 假设从数据库获取用户信息进行验证
String username = (String) token.getPrincipal();
String password = new String((char[]) token.getCredentials());
// 这里应该查询数据库验证用户信息
if ("user".equals(username) && "password".equals(password)) {
return new SimpleAuthenticationInfo(username, password, getName());
} else {
throw new AuthenticationException("用户名或密码错误");
}
}
// 用于授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
String username = (String) principals.getPrimaryPrincipal();
// 这里应该查询数据库获取用户的角色和权限信息并添加到authorizationInfo
if ("user".equals(username)) {
authorizationInfo.addRole("user");
authorizationInfo.addStringPermission("user:read");
}
return authorizationInfo;
}
}
五、加密
- Shiro提供了加密功能来保护用户密码等敏感信息。
1. 哈希算法使用示例
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
// 使用MD5算法进行加密
String password = "password";
String salt = "salt";
int hashIterations = 1024;
SimpleHash hash = new SimpleHash("md5", password, ByteSource.Util.bytes(salt), hashIterations);
System.out.println("加密后的密码: " + hash.toHex());
这只是一个Shiro的基础学习教程,Shiro还有很多高级特性,如多Realm配置、缓存机制等,可以根据实际需求进一步深入学习。