如果你对shiro有问题的话,请看这篇文章:Springboot+shiro,完整教程,带你学会shiro
第一步,先准备数据库:
数据库需要准备三个表,一个user表,一个role表,一个permission表。
user表:
CREATE TABLE `user` (
`id` int NOT NULL,
`username` varchar(100) DEFAULT NULL,
`password` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
role表:
CREATE TABLE `role` (
`id` int NOT NULL,
`name` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
permission表:
CREATE TABLE `permission` (
`id` int NOT NULL,
`name` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
然后插入数据:
第一个是user表,第二个是permission表,第三个是role表。大家自己建就是了。
第二步就是创建springboot项目,并操作数据库。
pom文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.tianfan</groupId>
<artifactId>shiroTest</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.9.1</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.mybatis.spring.boot</groupId>-->
<!-- <artifactId>mybatis-spring-boot-starter</artifactId>-->
<!-- <version>3.0.0</version>-->
<!-- </dependency>-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.21</version>
<scope>test</scope>
</dependency>
<!-- springbootweb-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.7</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</project>
application文件:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://localhost:3306/tianfan?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
配置实体类:
user类:
package org.tianfan.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User implements Serializable {
private Long id;
private String username;
private String password;
}
Role类:
package org.tianfan.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Role implements Serializable {
private Long id;
private String name;
// getter and setter
}
permission类:
package org.tianfan.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Permission implements Serializable {
private Long id;
private String name;
// getter and setter
}
准备mapper
PermissionMapper
package org.tianfan.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.tianfan.pojo.Permission;
public interface PermissionMapper extends BaseMapper<Permission> {
}
RoleMapper
package org.tianfan.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.tianfan.pojo.Role;
public interface RoleMapper extends BaseMapper<Role> {
}
UserMapper
package org.tianfan.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.tianfan.pojo.User;
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
准备service
UserService:
package org.tianfan.service;
import org.apache.ibatis.annotations.Mapper;
import org.tianfan.pojo.Permission;
import org.tianfan.pojo.Role;
import org.tianfan.pojo.User;
import java.util.List;
public interface UserService {
User findByUsername(String username);
List<Role> findRolesByUserId(Long userId);
List<Permission> findPermissionsByRoleId(Long roleId);
}
准备serviceImpl
UserServiceImpl
package org.tianfan.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.tianfan.mapper.PermissionMapper;
import org.tianfan.mapper.RoleMapper;
import org.tianfan.mapper.UserMapper;
import org.tianfan.pojo.Permission;
import org.tianfan.pojo.Role;
import org.tianfan.pojo.User;
import org.tianfan.service.UserService;
import java.util.ArrayList;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserMapper userMapper;
@Autowired
RoleMapper roleMapper;
@Autowired
PermissionMapper permissionMapper;
@Override
public User findByUsername(String username) {
LambdaQueryWrapper<User> lambdaQueryWrapper=new LambdaQueryWrapper();
lambdaQueryWrapper.eq(User::getUsername,username);
User user = userMapper.selectOne(lambdaQueryWrapper);
System.out.println(user);
return user;
}
@Override
public List<Role> findRolesByUserId(Long userId) {
LambdaQueryWrapper lambdaQueryWrapper=new LambdaQueryWrapper();
lambdaQueryWrapper.eq("id",userId);
Role role = roleMapper.selectOne(lambdaQueryWrapper);
List<Role> list=new ArrayList<>();
list.add(role);
return list;
}
@Override
public List<Permission> findPermissionsByRoleId(Long roleId) {
LambdaQueryWrapper lambdaQueryWrapper=new LambdaQueryWrapper();
lambdaQueryWrapper.eq("id",roleId);
Permission permission = permissionMapper.selectOne(lambdaQueryWrapper);
List<Permission> list=new ArrayList<>();
list.add(permission);
return list;
}
}
现在为止,开始配置shiro
配置一下ShiroConfig,配置那些比如说shiro要过滤的请求,securityManager(管理shiro对象的类)拿到主体的关键类,MyShiroRealm认证规格类,LifecycleBeanPostProcessor,用于在Spring容器中管理Shiro的生命周期。
package org.tianfan.config;
import org.apache.shiro.mgt.SessionsSecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.apache.shiro.mgt.SecurityManager;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/login.html", "anon");
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public SessionsSecurityManager securityManager(MyShiroRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//配置realm
securityManager.setRealm(userRealm);
return securityManager;
}
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm = new MyShiroRealm();
return myShiroRealm;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
MyShiroRealm认证规格类:
package org.tianfan.config;
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.tianfan.service.UserService;
import org.tianfan.pojo.Permission;
import org.tianfan.pojo.Role;
import org.tianfan.pojo.User;
import org.tianfan.service.impl.UserServiceImpl;
import java.util.List;
public class MyShiroRealm extends AuthorizingRealm {
@Autowired
private UserServiceImpl userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
User user = (User) principalCollection.getPrimaryPrincipal();
List<Role> roles = userService.findRolesByUserId(user.getId());
for (Role role : roles) {
authorizationInfo.addRole(role.getName());
List<Permission> permissions = userService.findPermissionsByRoleId(role.getId());
for (Permission permission : permissions) {
authorizationInfo.addStringPermission(permission.getName());
}
}
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
System.out.println(token.getUsername());
User user = userService.findByUsername(token.getUsername());
if (user == null) {
throw new UnknownAccountException();
}
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
}
}
现在就可以测试了,Contoller类:
package org.tianfan.contoller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.tianfan.pojo.User;
import org.tianfan.service.UserService;
@RestController
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/login")
public String login( String username, String password) {
System.out.println(username+password);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
subject.login(token);
return "登录成功";
} catch (AuthenticationException e) {
return "用户名或密码错误";
}
}
@GetMapping("/user")
public User getUser() {
Subject subject = SecurityUtils.getSubject();
return (User) subject.getPrincipal();
}
@GetMapping("/admin")
public String admin() {
return "admin";
}
}
主类:
package org.tianfan;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class);
}
}
前端页面login.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录表单</title>
<style type="text/css">
body {
background-color: #333;
font-family: Arial, sans-serif;
font-size: 14px;
color: #fff;
}
.container {
margin: 0 auto;
width: 400px;
padding: 20px;
background-color: #444;
border-radius: 5px;
box-shadow: 0 0 10px #000;
}
h2 {
margin-top: 0;
text-align: center;
}
form {
display: block;
margin: 0;
padding: 0;
}
label {
display: block;
margin-bottom: 5px;
}
input[type="text"], input[type="password"], input[type="email"] {
display: block;
width: 100%;
padding: 10px;
margin-bottom: 10px;
border: none;
border-radius: 5px;
background-color: #555;
color: #fff;
font-size: 14px;
}
input[type="submit"], input[type="reset"] {
display: inline-block;
padding: 10px 20px;
margin-right: 10px;
border: none;
border-radius: 5px;
background-color: #f00;
color: #fff;
font-size: 14px;
cursor: pointer;
}
input[type="submit"]:hover, input[type="reset"]:hover {
background-color: #c00;
}
.third-party {
margin-top: 20px;
text-align: center;
}
.third-party a {
display: inline-block;
margin-right: 10px;
border-radius: 50%;
background-color: #fff;
color: #000;
font-size: 20px;
line-height: 40px;
width: 40px;
height: 40px;
text-align: center;
text-decoration: none;
transition: all 0.3s ease;
}
.third-party a:hover {
background-color: #000;
color: #fff;
}
</style>
</head>
<body>
<div class="container">
<h2>登录</h2>
<form action="http://localhost:8080/login" method="post" name="login-form">
<label for="username">用户名</label>
<input type="text" id="username" name="username" required>
<label for="password">密码</label>
<input type="password" id="password" name="password" required>
<input type="submit" value="登录">
<input type="reset" value="重置">
</form>
<div class="third-party">
<a href="#">QQ</a>
<a href="#">微信</a>
<a href="#">微博</a>
</div>
</div>
</body>
</html>
运行启动结果图:
输入正确的密码:
之后就可以直接访问
如果没有登录正确的账号信息的话,就不可以访问这个,并且会直接跳转到login.jsp
如果你对shiro有问题的话,请看这篇文章:Springboot+shiro,完整教程,带你学会shiro