1,目录结构如下
2.导包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<!--使用Druid这个连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--spring对shiro的支持-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
3.application.properties里的配置内容
#配置模板引擎thymeleaf
#前缀
spring.thymeleaf.prefix=classpath:/templates/
#后缀
spring.thymeleaf.suffix=.html
#版本
spring.thymeleaf.mode=HTML5
#语言
spring.thymeleaf.encoding=UTF-8
#缓存
spring.thymeleaf.cache=false
#给java实体取别名
mybatis.type-aliases-package=com.qf.shiro.pojo
#告诉他mapper.xml文件所在的位置
mybatis.mapper-locations=classpath:mapper/*.xml
#连接数据库的配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql:///NZ1904
spring.datasource.username=root
spring.datasource.password=root
#设置连接池的类型
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#给应用取名字
spring.application.name=springboot-shiro
4,编写工具类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable{
private static final long serialVersionUID = 1841757056845722315L;
private int id;
private String userName;
private String password;
private String salt;
}
5,编写AppConfig.java文件
@SpringBootConfiguration //表示是一个配置文件
@ComponentScan(basePackages = {"com.qf.shiro"}) //这个就是原来spring配置中的扫描
@MapperScan(basePackages = {"com.qf.shiro.mapper"}) //这个是扫描 mapper接口所在的位置
public class AppConfig {
}
6,编写,UserMapper.java文件
public interface UserMapper {
/**
* 通过用户名查找用户对象
*/
User findUserByUserName(String userName);
}
7,编写UserMapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qf.shiro.mapper.UserMapper">
<select id="findUserByUserName" resultType="User">
SELECT * FROM t_user WHERE userName=#{userName}
</select>
</mapper>
8, 编写IUService.java文件
public interface IUserService {
User findUserByUserName(String userName);
}
9,编写UserService.java文件
@Service
@Transactional
public class UserService implements IUserService {
@Autowired
private UserMapper userMapper;
@Override
public User findUserByUserName(String userName) {
User user = userMapper.findUserByUserName(userName);
return user;
}
}
10,编写ShiroConfig.java文件
@SpringBootConfiguration
public class ShiroConfig {
//日志
private Logger logger = LoggerFactory.getLogger(ShiroConfig.class);
//配置过滤器拦截请求(注入安全管理器)
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
logger.info("shiro的过滤器执行了");
//如果认证没有通过,跳转到登陆页面
shiroFilterFactoryBean.setLoginUrl("/toLogin");
Map<String,String> maps = new LinkedHashMap<>();
//放行请求的地址
maps.put("/login","anon");
maps.put("/logout","logout");
maps.put("/**","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(maps);
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}
//配置安全管理器
@Bean
public DefaultWebSecurityManager securityManager(@Qualifier("myRealm")MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
logger.info("securityManager的过滤器执行了");
//校验的realm对象
securityManager.setRealm(myRealm);
return securityManager;
}
//配置realm
@Bean
public MyRealm myRealm(){
MyRealm myRealm = new MyRealm();
logger.info("myRealm的过滤器执行了");
myRealm.setCredentialsMatcher( hashedCredentialsMatcher());
return myRealm;
}
//配置密码散列
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
//设置散列方法
matcher.setHashAlgorithmName("MD5");
//设置散列次数
matcher.setHashIterations(1);
return matcher;
}
}
11,编写MyRealm文件
public class MyRealm extends AuthorizingRealm {
@Autowired
private IUserService userService;
@Override
public String getName(){
return "MyRealm";
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获取前端传的用户名
String userName = (String) authenticationToken.getPrincipal();
//通过用户名查询用户对象
User user = userService.findUserByUserName(userName);
//如果没查出来
if (user==null){
return null;
}
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
user,
user.getPassword(),
ByteSource.Util.bytes(user.getSalt()),
getName());
return simpleAuthenticationInfo;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
}
12,编写UserController
@Controller
public class UserController {
private Logger logger= LoggerFactory.getLogger(UserController.class);
@RequestMapping("/toLogin")
public String toLogin(){
return "Login";
}
@RequestMapping("/toIndex")
public String toIndex(){
return "index";
}
/**
* 登陆
*/
@RequestMapping(value = "login")
public String login(User user, Model model){
//封装成请求对象
UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), user.getPassword());
//获取登陆的主题对象
Subject subject = SecurityUtils.getSubject();
//登陆
try{
subject.login(token);
}catch (UnknownAccountException err){//用户名不对
logger.error("用户名不正确");
model.addAttribute("userNameError","用户名错误");
return "Login";
}catch (IncorrectCredentialsException err){//密码不对
logger.error("密码不正确");
model.addAttribute("passwordError","密码错误");
return "Login";
}catch (Exception err){
logger.error("其他问题导致登陆失败"+err.fillInStackTrace());
return "Login";
}
//首页要显示用户信息
//获取用户信息
User user1 = (User) SecurityUtils.getSubject().getPrincipal();
model.addAttribute("user",user1);
return "index";
}
}
13,编写index.xml文件
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>欢迎<span th:text="${user.userName}"></span>大爷再次回来...</h2><br>
<h2>this is index page , And you?</h2>
<a href="/logout">退出</a>
</body>
</html>
14,编写Login.xml文件,(L大写)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login" method="post">
用户名:<input type="text" name="userName"/><span th:text="${userNameError}"></span><br>
密码:<input type="password" name="password"><span th:text="${passwordError}"></span><br>
<input type="submit" value="登陆">
</form>
</body>
</html>