Spring Boot Shiro 基本使用
Apache Shiro 是一个强大且易于使用的Java安全框架,提供了身份验证、授权、加密和会话管理等功能。在Spring Boot应用程序中使用Shiro可以轻松地实现安全性。
本文将介绍如何在Spring Boot应用程序中使用Shiro进行身份验证和授权。
步骤
以下是使用Spring Boot Shiro进行身份验证和授权的步骤:
- 添加Shiro依赖项
在pom.xml文件中添加以下依赖项:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.7.1</version>
</dependency>
- 配置Shiro
在application.properties文件中添加以下配置:
# Shiro配置
shiro:
# 登录URL
loginUrl: /login
# 登录成功URL
successUrl: /index
# 未授权URL
unauthorizedUrl: /unauthorized
# Shiro过滤器链配置
filterChainDefinitions: /static/** = anon\n/login = anon\n/logout = logout\n/** = authc
在上面的示例中,我们配置了Shiro的登录URL、登录成功URL、未授权URL和过滤器链。我们使用filterChainDefinitions属性来指定URL模式和相应的过滤器。
- 创建ShiroRealm
创建一个名为ShiroRealm的Java类,用于实现Shiro的Realm接口。以下是示例代码:
@Component
public class ShiroRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
User user = (User) principals.getPrimaryPrincipal();
authorizationInfo.setRoles(userService.getRoles(user.getUsername()));
authorizationInfo.setStringPermissions(userService.getPermissions(user.getUsername()));
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
String username = usernamePasswordToken.getUsername();
User user = userService.getUserByUsername(username);
if (user == null) {
throw new UnknownAccountException();
}
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
}
}
在上面的示例中,我们创建了一个名为ShiroRealm的类,用于实现Shiro的Realm接口。我们使用@Component注解将该类标记为Spring组件。我们使用@Autowired注解注入UserService。我们实现了doGetAuthorizationInfo和doGetAuthenticationInfo方法,用于授权和身份验证。在doGetAuthorizationInfo方法中,我们获取用户的角色和权限,并将它们设置为授权信息。在doGetAuthenticationInfo方法中,我们获取用户名和密码,并将它们设置为身份验证信息。
- 创建ShiroFilter
创建一个名为ShiroFilter的Java类,用于实现Shiro的Filter接口。以下是示例代码:
@Component
public class ShiroFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
SecurityUtils.setSecurityManager(SecurityUtils.getSecurityManager());
Subject subject = SecurityUtils.getSubject();
if (!subject.isAuthenticated() && !subject.isRemembered()) {
WebUtils.issueRedirect(request, response, "/login");
return;
}
filterChain.doFilter(request, response);
}
}
在上面的示例中,我们创建了一个名为ShiroFilter的类,用于实现Shiro的Filter接口。我们使用@Component注解将该类标记为Spring组件。我们实现了doFilterInternal方法,用于处理HTTP请求。在该方法中,我们获取当前用户的主题,并检查用户是否已经通过身份验证或记住我。如果用户未通过身份验证或记住我,则将用户重定向到登录页面。
- 创建登录页面
创建一个名为login.html的HTML文件,用于显示登录页面。以下是示例代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<h1>Login</h1>
<form method="post" action="/login">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
<br>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
<br>
<input type="submit" value="Login">
</form>
</body>
</html>
在上面的示例中,我们创建了一个名为login.html的HTML文件,用于显示登录页面。我们使用form元素创建一个登录表单,其中包含用户名和密码字段。
- 创建授权页面
创建一个名为index.html的HTML文件,用于显示授权页面。以下是示例代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Index</title>
</head>
<body>
<h1>Index</h1>
<p>Welcome, ${user.username}!</p>
<p>Your roles are: ${user.roles}</p>
<p>Your permissions are: ${user.permissions}</p>
<a href="/logout">Logout</a>
</body>
</html>
在上面的示例中,我们创建了一个名为index.html的HTML文件,用于显示授权页面。我们使用${user.username}、${user.roles}和${user.permissions}表达式显示当前用户的用户名、角色和权限。我们使用元素创建一个注销链接。
- 创建未授权页面
创建一个名为unauthorized.html的HTML文件,用于显示未授权页面。以下是示例代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Unauthorized</title>
</head>
<body>
<h1>Unauthorized</h1>
<p>You are not authorized to access this page.</p>
<a href="/login">Login</a>
</body>
</html>
在上面的示例中,我们创建了一个名为unauthorized.html的HTML文件,用于显示未授权页面。我们使用
元素显示未授权消息。我们使用元素创建一个登录链接。
- 创建UserController
创建一个名为UserController的Java类,用于处理HTTP请求。以下是示例代码:
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/index")
public ModelAndView index(Principal principal) {
ModelAndView modelAndView = new ModelAndView("index");
User user = userService.getUserByUsername(principal.getName());
modelAndView.addObject("user", user);
return modelAndView;
}
@GetMapping("/unauthorized")
public String unauthorized() {
return "unauthorized";
}
}
在上面的示例中,我们创建了一个名为UserController的类,用于处理HTTP请求。我们使用@RestController注解将该类标记为Spring MVC控制器。我们使用@Autowired注解注入UserService。我们实现了index和unauthorized方法,用于显示授权和未授权页面。在index方法中,我们获取当前用户的用户名,并将其传递给UserService以获取用户信息。我们使用ModelAndView对象返回index.html视图,并将用户信息添加到模型中。
- 创建UserService
创建一个名为UserService的Java类,用于提供用户信息。以下是示例代码:
@Service
public class UserService {
private Map<String, User> users = new HashMap<>();
public UserService() {
User user1 = new User("admin", "admin", "admin");
user1.setRoles(Arrays.asList("admin"));
user1.setPermissions(Arrays.asList("user:list", "user:add", "user:edit", "user:delete"));
users.put(user1.getUsername(), user1);
User user2 = new User("user", "user", "user");
user2.setRoles(Arrays.asList("user"));
user2.setPermissions(Arrays.asList("user:list"));
users.put(user2.getUsername(), user2);
}
public User getUserByUsername(String username) {
return users.get(username);
}
public List<String> getRoles(String username) {
User user = getUserByUsername(username);
return user.getRoles();
}
public List<String> getPermissions(String username) {
User user = getUserByUsername(username);
return user.getPermissions();
}
}
在上面的示例中,我们创建了一个名为UserService的类,用于提供用户信息。我们使用@Service注解将该类标记为Spring服务。我们使用Map
示例
以下是两个示例,演示如何使用Spring Boot Shiro进行身份验证和授权。
示例一:基本身份验证
在本示例中,我们将演示如何使用Spring Boot Shiro进行基本身份验证。
- 创建一个名为UserController的Java类,用于处理HTTP请求。以下是示例代码:
@RestController
public class UserController {
@GetMapping("/index")
public String index() {
return "Welcome to the index page!";
}
}
在上面的示例中,我们创建了一个名为UserController的类,用于处理HTTP请求。我们使用@RestController注解将该类标记为Spring MVC控制器。我们实现了index方法,用于显示欢迎消息。
- 创建一个名为ShiroRealm的Java类,用于实现Shiro的Realm接口。以下是示例代码:
@Component
public class ShiroRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
String username = usernamePasswordToken.getUsername();
String password = new String(usernamePasswordToken.getPassword());
if (!"admin".equals(username) || !"admin".equals(password)) {
throw new IncorrectCredentialsException();
}
return new SimpleAuthenticationInfo(username, password, getName());
}
}
在上面的示例中,我们创建了一个名为ShiroRealm的类,用于实现Shiro的Realm接口。我们使用@Component注解将该类标记为Spring组件。我们实现了doGetAuthenticationInfo方法,用于身份验证。在该方法中,我们获取用户名和密码,并将它们与预定义的值进行比较。如果用户名或密码不正确,则抛出IncorrectCredentialsException异常。
- 创建一个名为ShiroFilter的Java类,用于实现Shiro的Filter接口。以下是示例代码:
@Component
public class ShiroFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
SecurityUtils.setSecurityManager(SecurityUtils.getSecurityManager());
Subject subject = SecurityUtils.getSubject();
if (!subject.isAuthenticated() && !subject.isRemembered()) {
WebUtils.issueRedirect(request, response, "/login");
return;
}
filterChain.doFilter(request, response);
}
}
在上面的示例中,我们创建了一个名为ShiroFilter的类,用于实现Shiro的Filter接口。我们使用@Component注解将该类标记为Spring组件。我们实现了doFilterInternal方法,用于处理HTTP请求。在该方法中,我们获取当前用户的主题,并检查用户是否已经通过身份验证或记住我。如果用户未通过身份验证或记住我,则将用户重定向到登录页面。
- 创建一个名为login.html的HTML文件,用于显示登录页面。以下是示例代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<h1>Login</h1>
<form method="post" action="/login">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
<br>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
<br>
<input type="submit" value="Login">
</form>
</body>
</html>
在上面的示例中,我们创建了一个名为login.html的HTML文件,用于显示登录页面。我们使用form元素创建一个登录表单,其中包含用户名和密码字段。
- 配置Shiro
在application.properties文件中添加以下配置:
# Shiro配置
shiro:
# 登录URL
loginUrl: /login
# 登录成功URL
successUrl: /index
# 未授权URL
unauthorizedUrl: /unauthorized
# Shiro过滤器链配置
filterChainDefinitions: /static/** = anon\n/login = anon\n/logout = logout\n/** = authc
在上面的示例中,我们配置了Shiro的登录URL、登录成功URL、未授权URL和过滤器链。我们使用filterChainDefinitions属性来指定URL模式和相应的过滤器。
- 运行该应用程序,并访问http://localhost:8080/index。您应该会看到一个登录页面。输入用户名和密码“admin”,然后单击“登录”按钮。您应该会看到一个欢迎消息。
示例二:基本授权
在本示例中,我们将演示如何使用Spring Boot Shiro进行基本授权。
- 创建一个名为UserController的Java类,用于处理HTTP请求。以下是示例代码:
@RestController
public class UserController {
@GetMapping("/index")
public String index() {
return "Welcome to the index page!";
}
@GetMapping("/admin")
public String admin() {
return "Welcome to the admin page!";
}
}
在上面的示例中,我们创建了一个名为UserController的类,用于处理HTTP请求。我们使用@RestController注解将该类标记为Spring MVC控制器。我们实现了index和admin方法,用于显示欢迎消息。
- 创建一个名为ShiroRealm的Java类,用于实现Shiro的Realm接口。以下是示例代码:
@Component
public class ShiroRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
User user = (User) principals.getPrimaryPrincipal();
if ("admin".equals(user.getUsername())) {
authorizationInfo.addRole("admin");
authorizationInfo.addStringPermission("user:list");
authorizationInfo.addStringPermission("user:add");
authorizationInfo.addStringPermission("user:edit");
authorizationInfo.addStringPermission("user:delete");
} else {
authorizationInfo.addRole("user");
authorizationInfo.addStringPermission("user:list");
}
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
String username = usernamePasswordToken.getUsername();
String password = new String(usernamePasswordToken.getPassword());
if (!"admin".equals(username) || !"admin".equals(password)) {
throw new IncorrectCredentialsException();
}
return new SimpleAuthenticationInfo(new User(username, password), password, getName());
}
}
在上面的示例中,我们创建了一个名为ShiroRealm的类,用于实现Shiro的Realm接口。我们使用@Component注解将该类标记为Spring组件。我们实现了doGetAuthorizationInfo和doGetAuthenticationInfo方法,用于授权和身份验证。在doGetAuthorizationInfo方法中,我们获取用户的角色和权限,并将它们设置为授权信息。在doGetAuthenticationInfo方法中,我们获取用户名和密码,并将它们设置为身份验证信息。
- 创建一个名为ShiroFilter的Java类,用于实现Shiro的Filter接口。以下是示例代码:
@Component
public class ShiroFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
SecurityUtils.setSecurityManager(SecurityUtils.getSecurityManager());
Subject subject = SecurityUtils.getSubject();
if (!subject.isAuthenticated() && !subject.isRemembered()) {
WebUtils.issueRedirect(request, response, "/login");
return;
}
filterChain.doFilter(request, response);
}
}
在上面的示例中,我们创建了一个名为ShiroFilter的类,用于实现Shiro的Filter接口。我们使用@Component注解将该类标记为Spring组件。我们实现了doFilterInternal方法,用于处理HTTP请求。在该方法中,我们获取当前用户的主题,并检查用户是否已经通过身份验证或记住我。如果用户未通过身份验证或记住我,则将用户重定向到登录页面。
- 创建一个名为login.html的HTML文件,用于显示登录页面。以下是示例代码:
```html