Java Apache Shiro安全框架快速开发详解流程
什么是Apache Shiro
Apache Shiro是一个跨应用程序、支持单点登录、支持身份验证和访问控制框架,可以解决应用程序的安全问题。
Shiro的核心是将应用程序的用户身份、安全验证、访问控制等功能组合起来实现一个完整的安全框架。
使用Shiro开发的应用程序能够快速、安全地集成身份验证、安全验证、单点登录等功能。
Shiro框架的组件
Shiro由以下组件组成:
-
Subject:应用程序中的用户抽象对象,封装了与用户相关的对象和操作。
-
SecurityManager:Shiro框架的核心,用户管理、安全认证、访问控制等功能都与SecurityManager相关。
-
Authenticator:用于验证用户身份,提供不同的验证策略,如密码验证、指纹验证等。
-
Authorizer:用于授权用户访问资源,提供多种授权策略。
-
Realm:Shiro对数据源的抽象,用于获取用户身份认证信息和访问控制数据,可以将用户信息存储在数据库、LDAP或其他数据源中。
-
SessionManager:会话管理器,负责管理用户会话,可以定制不同的会话管理策略,如Cookie会话管理、URL会话跟踪等。
Shiro集成框架
在Java开发中,Shiro常常集成在一些框架中,如Spring、Struts等,通过集成Shiro,可以轻松地实现应用程序的安全模块。
下面就以Spring集成Shiro框架为例,介绍Shiro框架的快速开发流程。
快速搭建Shiro框架
在Spring应用程序中集成Shiro框架,通常需要完成以下步骤:
- 添加Shiro依赖:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.7.0</version>
</dependency>
- 配置Shiro相关组件:
<!-- 配置SecurityManager -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myRealm" />
</bean>
<!-- 配置Realm -->
<bean id="myRealm" class="xx.xx.xxx.MyRealm">
<!-- 配置数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置Shiro过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<!-- 配置过滤规则 -->
<property name="filterChainDefinitions">
<value>
/login.jsp = anon
/logout = logout
/** = authc
</value>
</property>
<!-- 配置登录URL -->
<property name="loginUrl" value="/login.jsp" />
<!-- 配置成功登录后的URL -->
<property name="successUrl" value="/index.jsp" />
<!-- 配置未登录时的URL -->
<property name="unauthorizedUrl" value="/unauthorized.jsp" />
</bean>
- 编写自定义Realm:
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
/**
* 授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 获取当前用户的角色和权限信息,并添加到authorizationInfo中
User user = (User)principals.getPrimaryPrincipal();
Set<String> roleNames = userService.findRoleNamesByUsername(user.getUsername());
authorizationInfo.setRoles(roleNames);
Set<String> permissions = userService.findPermissionsByUsername(user.getUsername());
authorizationInfo.setStringPermissions(permissions);
return authorizationInfo;
}
/**
* 认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
// 根据用户名和密码查询用户信息
User user = userService.findByUsernameAndPassword(upToken.getUsername(), new String(upToken.getPassword()));
if (user != null) {
// 如果用户存在返回一个身份认证信息
AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
return authenticationInfo;
}
throw new UnknownAccountException("用户名或密码错误");
}
}
以上代码中,MyRealm类中的doGetAuthenticationInfo方法用于根据用户名和密码查询用户信息,如果找到用户信息则返回一个身份认证信息。
doGetAuthorizationInfo方法用于根据PrincipalCollection对象获取当前用户的角色和权限信息,并添加到相应的授权信息中。
- 使用Shiro相关API实现身份验证和访问控制:
// 获取Subject对象
Subject subject = SecurityUtils.getSubject();
// 构造UsernamePasswordToken对象
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
// 身份验证
subject.login(token);
} catch (AuthenticationException e) {
// 身份验证失败
}
if (subject.isAuthenticated()) {
// 访问控制
if (subject.hasRole("admin")) {
// admin用户的操作
}
if (subject.isPermitted("user:create")) {
// 创建用户操作
}
}
以上代码中,使用SecurityUtils.getSubject()方法获取当前用户对象,使用UsernamePasswordToken构造方法构造身份认证信息。
通过subject.login(token)方法进行身份验证,subject.hasRole()和subject.isPermitted()方法进行访问控制。
示例1:使用Shiro实现用户登录认证
- 创建login.jsp文件,并添加一个简单的表单用于用户登录:
<form action="/login" method="post">
<input type="text" name="username" placeholder="用户名">
<input type="password" name="password" placeholder="密码">
<input type="submit" value="登录">
</form>
- 在Spring应用程序中配置Shiro相关组件,并添加用户登录控制器:
@Controller
public class LoginController {
@RequestMapping("/login")
public String login(HttpServletRequest request) {
// 获取Subject对象
Subject subject = SecurityUtils.getSubject();
// 获取请求参数
String username = request.getParameter("username");
String password = request.getParameter("password");
// 构造UsernamePasswordToken对象
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
// 身份验证
subject.login(token);
// 身份验证成功跳转到首页
return "redirect:/index";
} catch (AuthenticationException e) {
// 身份验证失败跳转到登录页面,显示错误信息
request.setAttribute("error", "用户名或密码错误");
return "login";
}
}
}
- 在MyRealm类中实现doGetAuthenticationInfo方法用于根据用户名和密码查询用户信息:
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
// 根据用户名和密码查询用户信息
User user = userService.findByUsernameAndPassword(upToken.getUsername(), new String(upToken.getPassword()));
if (user != null) {
// 如果用户存在返回一个身份认证信息
AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
return authenticationInfo;
}
throw new UnknownAccountException("用户名或密码错误");
}
- 运行应用程序并访问/login,输入用户名和密码进行登录认证。
示例2:使用Shiro实现角色授权和资源保护
- 在数据库中创建用户、角色和权限三张表,并添加测试数据:
CREATE TABLE `user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL DEFAULT '',
`password` varchar(32) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `role` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `permission` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `user` (`id`, `username`, `password`) VALUES
(1, 'admin', 'admin'),
(2, 'user', 'user');
INSERT INTO `role` (`id`, `name`) VALUES
(1, 'admin'),
(2, 'user');
INSERT INTO `permission` (`id`, `name`) VALUES
(1, 'user:read'),
(2, 'user:create'),
(3, 'user:update'),
(4, 'user:delete');
- 在MyRealm类中实现doGetAuthorizationInfo方法,使用userService.findRoleNamesByUsername()和userService.findPermissionsByUsername()方法查询当前用户的角色和权限信息,并添加到authorizationInfo对象中:
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
User user = (User)principals.getPrimaryPrincipal();
Set<String> roleNames = userService.findRoleNamesByUsername(user.getUsername());
authorizationInfo.setRoles(roleNames);
Set<String> permissions = userService.findPermissionsByUsername(user.getUsername());
authorizationInfo.setStringPermissions(permissions);
return authorizationInfo;
}
- 在Spring应用程序中配置Shiro相关组件,并添加用户列表控制器:
@Controller
public class UserController {
@RequestMapping("/users")
public String list() {
// 访问控制,如果用户没有"admin"角色或"users:view"权限,则禁止访问
Subject subject = SecurityUtils.getSubject();
if (!subject.hasRole("admin") && !subject.isPermitted("users:view")) {
throw new UnauthorizedException("没有访问权限");
}
// 查询用户列表,并返回到users.jsp页面
List<User> userList = userService.findAll();
return "users";
}
}
- 在Spring应用程序中修改Shiro过滤器,使用perms和roles配置用户访问控制规则:
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myRealm" />
<property name="sessionManager" ref="sessionManager" />
</bean>
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="globalSessionTimeout" value="3600000" />
<property name="deleteInvalidSessions" value="true" />
<property name="sessionDAO" ref="sessionDAO" />
</bean>
<bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
<property name="cacheManager" ref="cacheManager" />
</bean>
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:ehcache.xml" />
</bean>
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="filterChainDefinitions">
<value>
/login.jsp = anon
/logout = logout
/users = authc, perms[users:view], roles[admin]
/** = authc
</value>
</property>
<property name="loginUrl" value="/login.jsp" />
<property name="successUrl" value="/index.jsp" />
<property name="unauthorizedUrl" value="/unauthorized.jsp" />
</bean>
- 运行应用程序并访问/users,如果当前用户没有"admin"角色或者"users:view"权限,则禁止访问;如果有访问权限,则显示用户列表。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java Apache Shiro安全框架快速开发详解流程 - Python技术站