目录结构:
导包
shiro:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.6.0</version>
</dependency>
thymeleaf模板:
<!--thymeleaf模板-->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
themyleaf html头文件
<html lang="en" xmlns:th="http://www.thymeleaf.org">//thymeleaf可提示文件
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-security4">//security和thymeleaf整合时的前端头文件
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">//shiro和thymeleaf整合时的前端头文件
日志配置
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
</dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
druid
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
mysql
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
mybatis
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version> 2.1.1</version>
</dependency>
lombok
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
application.yml
spring:
datasource:
username: root
password: root
#?serverTimezone=UTC解决时区的报错
url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
#更换数据库为druid
type: com.alibaba.druid.pool.DruidDataSource
#Spring Boot 默认是不注入这些属性值的,需要自己绑定
#druid 数据源专有配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
#配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
#如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.Priority
#则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
#mybatis的配置文件
mybatis.type-aliases-package=com.example.pojo 别名
mybatis.config-location=classpath:mapper/*.xml mapper.xml文件的位置
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
shiroconfig:
@Configuration
public class ShiroConfig {
//ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean shiroFilterBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityM)
{
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityM);
// 添加shiro内置过滤器
/*
anon:无需认证可访问
authc:必须认证才能访问
user:必须拥有 记住我 才能访问
perms:拥有某个资源才可访问
role:拥有某个角色权限才可以访问
*/
Map<String,String> filtermap = new LinkedHashMap<String,String>();
// 添加通过权限要求
filtermap.put("/user/add","perms[user:add]");
filtermap.put("/user/update","perms[user:update]");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filtermap);
// 登录的页面
shiroFilterFactoryBean.setLoginUrl("/login");
// 登录成功页面
shiroFilterFactoryBean.setSuccessUrl("/index");
// 未授权的页面
shiroFilterFactoryBean.setUnauthorizedUrl("/unauth");
return shiroFilterFactoryBean;
}
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityM(@Qualifier("userRealm") UserRealm userRealm)
{
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
return securityManager;
}
//创建自定义的realm对象
@Bean
public UserRealm userRealm()
{
return new UserRealm();
}
//整合thymeleaf和shiro
@Bean
public ShiroDialect shiroDialect()
{
return new ShiroDialect();
}
}
UserRealm
public class UserRealm extends AuthorizingRealm{
@Autowired
UserService userService;
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 获取对象
Subject subject = SecurityUtils.getSubject();
User currentUser = (User) subject.getPrincipal();
//currentUser.getPerm() 查询当前对象权限,将权限添加进去
info.addStringPermission(currentUser.getPerm());
System.out.println("执行授权");
return info;
}
// 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行认证");
//获取用户token信息
UsernamePasswordToken usertoken = (UsernamePasswordToken)token;
// 查询出来用户信息
User user = userService.query(usertoken.getUsername());
if (user==null)
{
return null;
}
//将信息放入session,传给前端
Subject currentSubject = SecurityUtils.getSubject();
Session session = currentSubject.getSession();
session.setAttribute("loginUser",user);
// 密码shiro帮助判断
return new SimpleAuthenticationInfo(user,user.getPassword(),"");
}
}
controller
@Controller
public class TestController {
@RequestMapping("/index")
public String index()
{
return "index";
}
@RequestMapping("/user/add")
public String add()
{
return "user/add";
}
@RequestMapping("/user/update")
public String update()
{
return "user/update";
}
@RequestMapping("/login")
public String login(String account, String password, Model model) {
// 获取当前用户
Subject subject = SecurityUtils.getSubject();
//封装用户登录数据
UsernamePasswordToken token = new UsernamePasswordToken(account,password);
try {
subject.login(token);//执行登录方法,没有异常就好了这个login是默认的登录方法,不是自定义的
return "index";
} catch (UnknownAccountException e) {
model.addAttribute("msg", "用户名错误");
return "login";
} catch (IncorrectCredentialsException e) {
model.addAttribute("msg", "密码错误");
return "login";
}
}
@RequestMapping("/unauth")
@ResponseBody
public String unauth() {
return "未授权";
}
}
mapper
@Mapper
@Repository
public interface UserMapper {
User query(String account);
}
pojo
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String account;
private String password;
private String perm;
}
service
public interface UserService {
User query(String account);
}
serviceImpl
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserMapper userMapper;
@Override
public User query(String account) {
return userMapper.query(account);
}
}
mapper.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.example.mapper.UserMapper">
<select id="query" resultType="User" parameterType="String">
select * from android.student where account = #{account}
</select>
</mapper>
index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>首页</h1>
<!--从session中获取值-->
<div th:if="${session.loginUser}==null">
<a th:href="@{/Login}">登录</a>
</div>
<div shiro:hasPermission="user:add" >
<a th:href="@{/user/add}">add</a>
</div>
<div shiro:hasPermission="user:update" >
<a th:href="@{/user/update}">update</a>
</div>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p th:text="${msg}" style="color: red"></p>
<form th:action="@{/login}">
姓名:<input type="text" name="account">
密码:<input type="password" name="password">
<input type="submit" value="提交">
</form>
</body>
</html>
add.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
add
</body>
</html>
update.html’
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
update
</body>
</html>
记住mapper放置的位置:直接在mapper下