Shiro如何和数据库交互:Shiro通过Realm实现与数据库的交互、使用DAO模式封装数据访问逻辑、结合ORM框架如MyBatis或Hibernate、实现用户认证和授权功能。 其中,Shiro通过Realm实现与数据库的交互是关键步骤。Realm是Shiro的核心组件,用于获取用户、角色、权限等数据,通常需要通过实现自定义的Realm类来完成数据库操作。通过Realm类,我们可以将数据库中的用户信息和权限信息加载到Shiro的安全管理体系中,实现认证和授权。
一、Shiro简介
Shiro是一个强大且灵活的Java安全框架,主要用于处理认证、授权、会话管理和加密等功能。Shiro的设计目标是简化安全管理,并且可以无缝集成到任何Java应用中。Shiro的核心组件包括Subject、SecurityManager和Realm,其中Realm是实现与数据源(如数据库)交互的关键。
1、Shiro的核心组件
Subject:表示当前用户,包含了用户的身份和权限信息。
SecurityManager:负责管理所有的Subject,类似于Spring Security中的SecurityContext。
Realm:用于从数据源中获取用户、角色和权限信息,是Shiro与数据库交互的核心组件。
2、Shiro的工作流程
Shiro的工作流程通常包括以下几个步骤:
- 用户提交认证请求(如登录)。
- Shiro的SecurityManager接收请求并将其委托给适当的Realm。
- Realm从数据源(如数据库)中获取用户信息,并进行认证和授权。
- 如果认证成功,用户即可访问受保护的资源;否则,访问被拒绝。
二、Realm与数据库交互
1、什么是Realm
Realm是Shiro用于连接数据源的桥梁,负责从数据源中获取用户信息和权限信息。实现自定义的Realm类,可以将数据库中的用户数据加载到Shiro中。
2、如何实现自定义Realm
实现自定义Realm的步骤如下:
- 创建一个继承
AuthorizingRealm
的类。 - 实现
doGetAuthenticationInfo
方法,用于获取用户的认证信息。 - 实现
doGetAuthorizationInfo
方法,用于获取用户的授权信息。
public class MyRealm extends AuthorizingRealm {
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
// 从数据库获取用户信息
User user = userService.findByUsername(username);
if (user == null) {
throw new UnknownAccountException(); // 用户不存在
}
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal();
// 从数据库获取用户角色和权限
Set<String> roles = userService.findRoles(username);
Set<String> permissions = userService.findPermissions(username);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
info.setStringPermissions(permissions);
return info;
}
}
3、集成ORM框架
在实际项目中,我们通常会结合ORM框架(如MyBatis或Hibernate)来实现数据库访问。下面以MyBatis为例,说明如何集成Shiro与数据库。
使用MyBatis与Shiro集成
- 配置MyBatis的Mapper接口和XML映射文件。
- 在自定义Realm中注入Mapper接口,使用MyBatis查询数据库。
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserMapper userMapper;
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
// 使用MyBatis查询数据库
User user = userMapper.findByUsername(username);
if (user == null) {
throw new UnknownAccountException(); // 用户不存在
}
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal();
// 使用MyBatis查询数据库
Set<String> roles = userMapper.findRoles(username);
Set<String> permissions = userMapper.findPermissions(username);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
info.setStringPermissions(permissions);
return info;
}
}
三、使用DAO模式封装数据访问逻辑
DAO(Data Access Object)模式是一种常见的数据访问设计模式,通过将数据访问逻辑封装在独立的类中,可以提高代码的可维护性和复用性。
1、定义DAO接口和实现类
首先,定义DAO接口和实现类,以封装数据库访问逻辑。
public interface UserDAO {
User findByUsername(String username);
Set<String> findRoles(String username);
Set<String> findPermissions(String username);
}
public class UserDAOImpl implements UserDAO {
@Autowired
private SqlSessionFactory sqlSessionFactory;
@Override
public User findByUsername(String username) {
try (SqlSession session = sqlSessionFactory.openSession()) {
return session.selectOne("UserMapper.findByUsername", username);
}
}
@Override
public Set<String> findRoles(String username) {
try (SqlSession session = sqlSessionFactory.openSession()) {
return new HashSet<>(session.selectList("UserMapper.findRoles", username));
}
}
@Override
public Set<String> findPermissions(String username) {
try (SqlSession session = sqlSessionFactory.openSession()) {
return new HashSet<>(session.selectList("UserMapper.findPermissions", username));
}
}
}
2、在Realm中使用DAO
在自定义Realm中注入DAO对象,调用DAO方法获取用户信息和权限信息。
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserDAO userDAO;
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
User user = userDAO.findByUsername(username);
if (user == null) {
throw new UnknownAccountException(); // 用户不存在
}
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal();
Set<String> roles = userDAO.findRoles(username);
Set<String> permissions = userDAO.findPermissions(username);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
info.setStringPermissions(permissions);
return info;
}
}
四、Shiro的认证与授权流程详解
1、认证流程
认证是指验证用户身份的过程,Shiro的认证流程如下:
- 用户提交登录请求,包含用户名和密码。
- Shiro的SecurityManager将请求委托给适当的Realm。
- Realm从数据库中获取用户信息,并验证密码是否匹配。
- 如果密码匹配,认证成功;否则,抛出认证异常。
在自定义Realm的doGetAuthenticationInfo
方法中,我们可以实现具体的认证逻辑。
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
User user = userDAO.findByUsername(username);
if (user == null) {
throw new UnknownAccountException(); // 用户不存在
}
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
}
2、授权流程
授权是指验证用户是否有权访问某个资源的过程,Shiro的授权流程如下:
- 用户访问受保护的资源。
- Shiro的SecurityManager将请求委托给适当的Realm。
- Realm从数据库中获取用户的角色和权限信息。
- 如果用户具有访问权限,授权成功;否则,抛出授权异常。
在自定义Realm的doGetAuthorizationInfo
方法中,我们可以实现具体的授权逻辑。
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal();
Set<String> roles = userDAO.findRoles(username);
Set<String> permissions = userDAO.findPermissions(username);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
info.setStringPermissions(permissions);
return info;
}
五、Shiro与Spring整合
在实际项目中,Shiro通常与Spring框架整合使用,以简化配置和管理。
1、Spring配置Shiro
在Spring配置文件中,配置Shiro的相关Bean,包括SecurityManager、Realm等。
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myRealm"/>
</bean>
<bean id="myRealm" class="com.example.MyRealm"/>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
2、Spring Boot配置Shiro
在Spring Boot项目中,可以通过配置类来集成Shiro。
@Configuration
public class ShiroConfig {
@Bean
public SecurityManager securityManager(MyRealm myRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
return securityManager;
}
@Bean
public MyRealm myRealm() {
return new MyRealm();
}
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
shiroFilter.setLoginUrl("/login");
shiroFilter.setUnauthorizedUrl("/unauthorized");
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/logout", "logout");
filterChainDefinitionMap.put("/", "authc");
shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilter;
}
}
六、Shiro缓存机制
为了提高性能,Shiro提供了缓存机制,可以缓存用户的认证和授权信息,减少数据库访问次数。
1、启用缓存
在自定义Realm中启用缓存,只需设置CachingRealm
的相关属性。
public class MyRealm extends AuthorizingRealm {
public MyRealm() {
setCachingEnabled(true);
setAuthenticationCachingEnabled(true);
setAuthorizationCachingEnabled(true);
setAuthenticationCacheName("authenticationCache");
setAuthorizationCacheName("authorizationCache");
}
// 认证和授权方法省略
}
2、配置缓存管理器
在Spring配置文件或Spring Boot配置类中,配置Shiro的缓存管理器。
@Bean
public EhCacheManager ehCacheManager() {
EhCacheManager cacheManager = new EhCacheManager();
cacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
return cacheManager;
}
@Bean
public SecurityManager securityManager(MyRealm myRealm, EhCacheManager ehCacheManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
securityManager.setCacheManager(ehCacheManager);
return securityManager;
}
七、Shiro与项目管理系统的集成
在开发和维护项目时,使用有效的项目管理系统可以提高团队的协作效率和项目进度的可控性。推荐使用以下两个系统:
1、研发项目管理系统PingCode
PingCode是一个专为研发团队设计的项目管理系统,提供了全面的项目规划、任务跟踪、版本管理等功能。通过集成Shiro,可以实现对项目管理系统的安全控制。
2、通用项目协作软件Worktile
Worktile是一个通用的项目协作软件,适用于各类团队和项目。Worktile提供了丰富的项目管理和协作工具,通过与Shiro的集成,可以提升系统的安全性和用户管理能力。
八、总结
Shiro是一个强大且灵活的Java安全框架,通过Realm实现与数据库的交互,可以方便地实现用户认证和授权功能。在实际项目中,结合DAO模式和ORM框架(如MyBatis或Hibernate),可以提高代码的可维护性和复用性。此外,通过与Spring或Spring Boot的整合,可以简化Shiro的配置和管理。启用Shiro的缓存机制,可以提升系统性能。最后,推荐使用PingCode和Worktile作为项目管理系统,以提高团队协作效率。
相关问答FAQs:
1. 如何在shiro中配置数据库交互?
在shiro中配置数据库交互需要进行以下步骤:
- 首先,确保在shiro配置文件中定义了数据源,例如使用JDBC数据源或者连接池。
- 其次,配置shiro的Realm,将Realm与数据库进行关联。通过Realm可以实现用户认证和授权的功能。
- 接下来,编写自定义的Realm实现类,其中包含了与数据库交互的逻辑。通过重写Realm的认证和授权方法,可以实现与数据库的交互。
- 最后,将自定义的Realm实例配置到shiro的配置文件中。
2. shiro如何实现用户登录时与数据库进行验证?
在shiro中,用户登录时与数据库进行验证的步骤如下:
- 用户输入用户名和密码后,shiro会调用自定义的Realm实现类中的认证方法。
- 在认证方法中,可以通过查询数据库来验证用户名和密码的正确性。可以使用JDBC或者ORM框架来进行数据库查询操作。
- 如果数据库中存在匹配的用户名和密码,则认证成功,shiro会继续执行后续的登录逻辑;否则认证失败,用户将无法登录。
3. 如何在shiro中实现动态授权?
在shiro中,可以通过与数据库交互来实现动态授权,具体步骤如下:
- 首先,在自定义的Realm实现类中重写授权方法,例如doGetAuthorizationInfo()方法。
- 在授权方法中,可以查询数据库获取用户的角色和权限信息。
- 根据用户的角色和权限信息,可以动态地为用户授权,例如设置用户的角色和权限集合。
- 最后,将授权信息返回给shiro,shiro会根据授权信息来判断用户是否有访问某个资源的权限。
原创文章,作者:Edit2,如若转载,请注明出处:https://docs.pingcode.com/baike/2161054