Shiro是一个强大且易用的Java安全框架,能够提供身份验证、授权、加密和会话管理等功能。Spring Boot则是一个用于快速搭建Spring应用的框架,简化了Spring应用的开发过程。将Shiro与Spring Boot集成,可以为Spring Boot应用添加强大的安全功能。下面将详细介绍Shiro与Spring Boot的集成指南。
环境准备
在开始集成之前,需要确保已经安装了Java开发环境(JDK 8及以上)和Maven。创建一个新的Spring Boot项目,可以使用Spring Initializr(https://start.spring.io/ )快速生成项目骨架,选择所需的依赖,如Spring Web。
添加Shiro依赖
在项目的pom.xml文件中添加Shiro与Spring Boot集成的依赖。以下是所需的依赖配置:
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Shiro Spring Boot Starter -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.9.1</version>
</dependency>
</dependencies>添加完依赖后,Maven会自动下载并管理这些依赖。
配置Shiro
创建一个Shiro配置类,用于配置Shiro的相关组件,如Realm、SecurityManager等。以下是一个示例配置类:
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 设置登录页面
shiroFilterFactoryBean.setLoginUrl("/login");
// 设置未授权页面
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
return shiroFilterFactoryBean;
}
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
// 配置哪些请求需要进行权限验证
chainDefinition.addPathDefinition("/login", "anon");
chainDefinition.addPathDefinition("/", "authc");
return chainDefinition;
}
}在上述配置中,shiroFilterFactoryBean方法用于创建Shiro的过滤器工厂,设置了登录页面和未授权页面。shiroFilterChainDefinition方法用于定义请求的过滤规则,这里配置了/login请求不需要进行身份验证,其他请求都需要进行身份验证。
创建自定义Realm
Realm是Shiro进行身份验证和授权的核心组件,需要创建一个自定义的Realm类来实现身份验证和授权逻辑。以下是一个示例:
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;
public class CustomRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 模拟添加角色和权限
authorizationInfo.addRole("admin");
authorizationInfo.addStringPermission("user:manage");
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername();
String password = new String(upToken.getPassword());
// 模拟验证
if (!"admin".equals(username)) {
throw new UnknownAccountException("用户名不存在");
}
if (!"123456".equals(password)) {
throw new IncorrectCredentialsException("密码错误");
}
return new SimpleAuthenticationInfo(username, password, getName());
}
}在CustomRealm类中,doGetAuthorizationInfo方法用于进行授权操作,这里模拟添加了一个admin角色和user:manage权限。doGetAuthenticationInfo方法用于进行身份验证,验证用户名和密码是否正确。
将自定义Realm注入到SecurityManager
需要将自定义的Realm注入到SecurityManager中,修改ShiroConfig类如下:
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ShiroConfig {
@Bean
public CustomRealm customRealm() {
return new CustomRealm();
}
@Bean
public SecurityManager securityManager(CustomRealm customRealm) {
org.apache.shiro.mgt.DefaultWebSecurityManager securityManager = new org.apache.shiro.mgt.DefaultWebSecurityManager();
securityManager.setRealm(customRealm);
return securityManager;
}
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 设置登录页面
shiroFilterFactoryBean.setLoginUrl("/login");
// 设置未授权页面
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
return shiroFilterFactoryBean;
}
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
// 配置哪些请求需要进行权限验证
chainDefinition.addPathDefinition("/login", "anon");
chainDefinition.addPathDefinition("/", "authc");
return chainDefinition;
}
}在上述代码中,customRealm方法创建了自定义的Realm实例,securityManager方法将自定义的Realm注入到SecurityManager中。
创建控制器
创建控制器来处理登录、未授权等请求。以下是一个示例:
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class LoginController {
@GetMapping("/login")
public String loginPage() {
return "login";
}
@PostMapping("/login")
public String login(@RequestParam String username, @RequestParam String password) {
Subject currentUser = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
currentUser.login(token);
return "redirect:/home";
} catch (UnknownAccountException | IncorrectCredentialsException e) {
return "redirect:/login?error=1";
} catch (AuthenticationException e) {
return "redirect:/login?error=2";
}
}
@GetMapping("/home")
public String homePage() {
return "home";
}
@GetMapping("/unauthorized")
public String unauthorizedPage() {
return "unauthorized";
}
}在上述控制器中,loginPage方法用于返回登录页面,login方法用于处理登录请求,根据登录结果进行相应的跳转。homePage方法用于返回主页,unauthorizedPage方法用于返回未授权页面。
创建视图页面
在src/main/resources/templates目录下创建登录页面login.html、主页home.html和未授权页面unauthorized.html。以下是一个简单的登录页面示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<h1>Login</h1>
<form action="/login" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
<input type="submit" value="Login">
</form>
<% if (request.getParameter("error") != null) { %>
<p style="color: red;">Invalid username or password<% } %>
</body>
</html>其他页面可以根据需要进行简单的设计。
测试集成效果
启动Spring Boot应用,访问应用的根路径,会自动跳转到登录页面。输入正确的用户名和密码(这里是admin和123456),点击登录按钮,会跳转到主页。如果输入错误的用户名或密码,会显示错误信息。如果访问需要权限的页面而没有相应的权限,会跳转到未授权页面。
通过以上步骤,就完成了Shiro与Spring Boot的集成。在实际项目中,可以根据需求进一步扩展和优化Shiro的配置,如使用数据库进行用户信息和权限信息的管理,实现更复杂的授权逻辑等。
