一,Shiro概念
Apache Shiro 是一个强大且易用的 Java 安全框架,它提供了身份验证、授权、加密和会话管理等功能。Shiro 的设计目标是简化应用程序的安全性,让开发者能够快速地集成安全特性,而无需深入了解复杂的安全概念。
二,Shiro功能
1. 身份验证(Authentication)
Shiro 支持多种身份验证机制,包括用户名/密码、LDAP、OAuth、OpenID 等。它提供了灵活的 API 来处理身份验证请求,允许开发者根据业务需求定制身份验证流程。UsernamePasswordToken 是 Shiro 中用于处理基于用户名和密码的身份验证的类。
2. 授权(Authorization)
Shiro 提供了基于角色的访问控制(RBAC)和基于权限的访问控制(PBAC)两种授权机制。它允许开发者定义角色和权限,并将它们关联到用户或资源上。在运行时,Shiro 会根据用户的角色和权限来决定是否允许其访问特定的资源或执行特定的操作。
3. 会话管理(Session Management)
Shiro 提供了强大的会话管理功能,包括会话创建、会话验证、会话超时等。它支持多种会话存储方式,如内存、数据库、缓存等。Shiro 的会话管理可以与 Servlet 容器(如 Tomcat)的会话管理集成,也可以独立使用。
4. 加密(Cryptography)
Shiro 提供了加密和哈希算法的实现,用于保护敏感数据(如密码)的存储和传输。它支持多种加密算法和哈希算法,并提供了简单易用的 API 来进行加密和哈希操作。
5. 集成性(Integration)
Shiro 可以轻松地与 Spring、Struts2、JSF 等主流 Java 框架集成,提供一致的安全解决方案。此外,Shiro 还提供了丰富的插件和扩展点,允许开发者根据需要进行定制和扩展。
6. 缓存(Caching)
Shiro 支持缓存机制,用于提高身份验证和授权的性能。它允许开发者配置缓存策略,将身份验证和授权的结果缓存起来,以减少对后端系统的访问次数。
7. 易于使用和配置
Shiro 的 API 设计简洁明了,易于学习和使用。同时,Shiro 提供了丰富的配置文件和注解支持,允许开发者通过配置文件或注解来配置安全策略,而无需编写大量的代码。
三,核心三大类
Subject:
在 Shiro 中,Subject 可以看作是当前与系统进行交互的用户或第三方服务。它是 Shiro 安全框架的入口点,提供了用户与应用程序安全交互的接口。通过 Subject,你可以执行如登录、注销、访问会话、执行授权检查等操作。
SecurityManager:
SecurityManager 是 Shiro 架构的心脏,它负责协调内部各安全组件,管理内部组件实例,并通过它来提供安全管理的各种服务。当 Shiro 与一个 Subject 进行交互时,实质上是幕后的 SecurityManager 处理所有繁重的 Subject 安全操作。你可以把它看成是一个前端控制器,它负责调度 Shiro 框架的各种服务。
Realms:
Realm 本质上是一个特定安全的 DAO(数据访问对象)。Realm 用于从数据源(如关系数据库、LDAP 服务器等)获取安全数据(如用户账号、角色和权限信息)。当 SecurityManager 需要验证用户身份或授权时,它会从配置的 Realms 中获取必要的信息来进行判断。Shiro 提供了多种可用的 Realms 实现,同时也支持自定义 Realm 来满足特定的业务需求。
四,简单使用
简单流程图

代码实现:
1,登录
@Override
public R userShiroLogin(UserLoginDTO userLoginDTO) {
try {
//1,密码校验
Integer level = PasswordVerifiersUtils.passwordStrong(userLoginDTO.getPassword());
if (level==0){
return R.error();
}
//2,密码加密
String password = DESEncryptionDecryptionUtils.encrypt(userLoginDTO.getPassword());
//获取当前的用户
Subject subject = SecurityUtils.getSubject();
//封装用户的登录数据
UsernamePasswordToken token = new UsernamePasswordToken(userLoginDTO.getUserName(), password);
try {
subject.login(token); //执行登录的方法,如果没有异常就说明ok
subject.isPermitted("admin");
Subject currentSubject = SecurityUtils.getSubject();
Session session = currentSubject.getSession();
log.info("Shiro-Session过期时间:" + session.getTimeout());
return R.ok("登录成功");
} catch (UnknownAccountException e) { //用户名不存在
return R.error("该用户不存在!");
} catch (IncorrectCredentialsException e) { //密码不存在
return R.error("密码错误!");
}
}catch (Exception e){
log.error("UserLoginServiceImpl.userShiroLogin error:{}",e);
return R.error();
}
}
2 ,配置Shiro
package com.zwxict.user.shiro;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import java.util.HashMap;
import java.util.Map;
/**
* Shiro配置类
* @author 汤义
* @create 2024-03-17:53
*/
@Configuration
public class ShiroConfig {
// 配置Realm
@Bean
public ShiroRealm realm() {
return new ShiroRealm();
}
// 配置SecurityManager
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm());
return securityManager;
}
// 配置ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
filterFactoryBean.setSecurityManager(securityManager);
// 配置登录页面
filterFactoryBean.setLoginUrl("/userLogin/login");
// 配置未授权页面
filterFactoryBean.setUnauthorizedUrl("/unauthorized");
// 配置拦截规则
Map<String, String> filterChainDefinitionMap = new HashMap<>();
filterChainDefinitionMap.put("/userLogin/login", "anon");
filterChainDefinitionMap.put("/userRegister/register", "anon");
filterChainDefinitionMap.put("/userLogin/shiro_login", "anon");
filterChainDefinitionMap.put("/**", "authc");
filterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return filterFactoryBean;
}
//配置session
@Bean(name = "sessionManager")
public DefaultWebSessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
// 设置session过期时间3600s
sessionManager.setGlobalSessionTimeout(3600000L);
return sessionManager;
}
}
3,Realm
package com.zwxict.user.shiro;
import com.zwxict.user.entity.UserEntity;
import com.zwxict.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Shiro身份认证和授权类
* @author 汤义
* @create 2024-03-17:53
*/
@Component
@Slf4j
public class ShiroRealm extends AuthorizingRealm {
@Autowired
UserService userService;
/**
* 身份授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 获取用户名
String username = (String) principalCollection.getPrimaryPrincipal();
// User user = userService.findByUsername(username);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// // 添加角色权限信息
// info.addRole(user.getRole());
// // 添加权限信息
// info.addStringPermission(user.getPermission());
return info;
}
/**
* 身份认证
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 根据用户名从数据库中查询用户信息
String username = (String) token.getPrincipal();
UserEntity user = userService.queryUser(username);
if(user == null) {
throw new UnknownAccountException();
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUserName(), user.getPassword(), getName());
return info;
}
}
这就是一个简单实现,实际使用后面在介绍。
本文介绍了ApacheShiro,一个强大的Java安全框架,涵盖了身份验证、授权、会话管理、加密、集成Spring等核心功能,以及Subject、SecurityManager和Realms等关键概念及其在简单应用中的使用示例。
625

被折叠的 条评论
为什么被折叠?



