Apache Shiro基本使用指南
文章目录
- 前言
- Shiro简介
- Shiro的核心概念
- 环境搭建
- 快速入门示例
- 1. 创建shiro.ini配置文件
- 2. 编写测试代码
- 自定义Realm
- 创建shiro.ini配置文件
- 创建自定义Realm类
- 测试结果
- 总结
前言
在Java Web开发中,安全框架的选择一直是开发者关注的重点。Spring Security功能强大但配置复杂,而Apache Shiro则以其简单易用、功能完整而受到广大开发者的喜爱。今天我们就来详细了解Shiro的基本使用,看看如何快速上手这个优秀的安全框架。
Shiro简介
Apache Shiro是一个功能强大且易于使用的Java安全框架,它可以帮助我们完成认证、授权、加密、缓存和会话管理等安全相关的功能。
Shiro的核心概念
- Subject(主体):当前用户,不一定是具体的人,也可能是第三方服务
- SecurityManager(安全管理器):Shiro的核心,协调各个组件工作
- Realm(域):数据源,负责获取安全数据(用户、角色、权限)
环境搭建
首先,我们需要在项目中引入Shiro的相关依赖。以Maven项目为例:
<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- Shiro核心依赖 --><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.3.2</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency>
</dependencies>
快速入门示例
让我们从一个最简单的示例开始,了解Shiro的基本工作流程。
1. 创建shiro.ini配置文件
在resources目录下创建shiro.ini
文件:
[users]
# 用户名=密码,角色1,角色2
zhang=123,admin
wang=456,user
li=789,user,manager[roles]
# 角色=权限1,权限2
admin=*
user=user:read,user:create
manager=user:*,order:read
2. 编写测试代码
public class ShiroQuickStart {public static void main(String[] args) {// 1. 获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManagerFactory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");// 2. 得到SecurityManager实例并绑定给SecurityUtilsSecurityManager securityManager = factory.getInstance();SecurityUtils.setSecurityManager(securityManager);// 3. 得到Subject及创建用户名/密码身份验证TokenSubject currentUser = SecurityUtils.getSubject();// 4. 登录if (!currentUser.isAuthenticated()) {UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");token.setRememberMe(true); try {currentUser.login(token);logger.info("用户登录成功");} catch (UnknownAccountException uae) {logger.error("用户不存在: " + token.getPrincipal());} catch (IncorrectCredentialsException ice) {logger.error("密码错误: " + token.getPrincipal());} catch (LockedAccountException lae) {logger.error("账户被锁定: " + token.getPrincipal());} catch (AuthenticationException ae) {logger.error("认证失败");}}// 5. 权限检查if (currentUser.hasRole("admin")) {logger.info("用户拥有admin角色");} else {logger.info("用户没有admin角色");}// 检查具体权限if (currentUser.isPermitted("user:create")) {logger.info("用户有创建用户的权限");} else {logger.info("用户没有创建用户的权限");}// 6. 退出登录currentUser.logout();}
}
自定义Realm
在实际项目中,我们通常需要从数据库获取用户信息,这时就需要自定义Realm。
创建shiro.ini配置文件
[main]
#声明realm
myClass = com.coldscholor.shiro.MyRealm
#注册realm到securityManager中
securityManager.realm = $myClass
创建自定义Realm类
/*** Realm域:Shiro从Realm获取安全数据(如用户、角色、权限),* 就是说SecurityManager要验证用户身份,那么它需要从Realm* 获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm* 得到用户相应的角色/权限进行验证用户是否能进行操作;可以把* Realm看成DataSource,即安全数据源* <p>* 自定义realms对象* 继承AuthorizingRealm* 重写方法* doGetAuthorizationInfo:授权* 获取到用户的授权数据(用户的权限数据)* doGetAuthenticationInfo:认证* 根据用户名密码登录,将用户数据保存(安全数据)*/
public class MyRealm extends AuthorizingRealm {public MyRealm() {// 设置密码匹配器HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(DigestsUtil.SHA1);// 设置迭代次数matcher.setHashIterations(DigestsUtil.COUNTS);// 设置加密方式setCredentialsMatcher(matcher);}/*** 授权* @param principalCollection* @return*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println("授权");// 获取用户名String username = (String) principalCollection.getPrimaryPrincipal();System.out.println("用户名:" + username);// 用户的权限数据List<String> perms = new ArrayList<>();perms.add("save");perms.add("update");perms.add("delete");perms.add("find");// 用户的角色数据List<String> roles = new ArrayList<>();roles.add("admin");roles.add("user");SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();info.addStringPermissions(perms);info.addRoles(roles);return info;}/*** 认证** @param authenticationToken* @return* @throws AuthenticationException*//*@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {System.out.println("认证");UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;String username = token.getUsername();String password = new String(token.getPassword());if ("admin".equals(username) && "123456".equals(password)) {// 参数:用户名,密码,当前realm对象的名称SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, getName());return info;} else {throw new RuntimeException("用户名或密码错误,认证失败");}}*//*** 对密文密码进行解密并认证* salt:是一个随机字符串,用于对密码进行加密* @param authenticationToken* @return* @throws AuthenticationException*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {System.out.println("认证");UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;String username = token.getUsername();SecurityService securityService = new SecurityServiceImpl();Map<String,String> map = securityService.findPasswordByLoginName(username);if(map == null){throw new RuntimeException("用户不存在");}String salt = map.get("salt");String password = map.get("password");//参数1:安全数据 参数2:密码 参数3:混淆字符串 参数4:realm名称SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, ByteSource.Util.bytes(salt), getName());return info;}
}
测试结果
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
认证
登录结果:true
总结
Apache Shiro作为一个轻量级的安全框架,具有简单易用、功能完整的特点。在实际项目中,建议根据具体的业务需求选择合适的配置方式,并结合缓存、异常处理等机制,构建一个安全、高效的权限管理系统。Shiro虽然简单,但功能强大。掌握了这些基本用法,相信你已经能够在项目中熟练使用Shiro来处理安全相关的需求了。