一、引入依赖
<!-- Spring Boot SpringMVC 框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
<!-- 热部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
<scope>true</scope>
</dependency>
<!-- MySQL 连接驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
<!--Mybatis-Plus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!-- thymeleaf依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- shiro依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!-- 配置数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<!-- thymeleaf-shiro依赖 -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
二、配置application.yml配置文件
# 配置端口号
server:
port: 8888
spring:
# 配置数据源
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/study?useSSL=false
username: root
password: admin
# 配置数据库连接池
type: com.alibaba.druid.pool.DruidDataSource
#配置MyBatis-Plus
mybatis-plus:
# 配置别名
type-aliases-package: com.wx.springboot_shiro.entity
# 配置xxxMapper.xml文件地址
mapper-locations:
classpath: mapper/*.xml
三、编写实体类 User
数据库表中的字段与实体类字段相同
直接使用lombok注解来进行有参无参构造和Getter/Setter方法
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private String password;
}
四、编写dao层user的mapper接口
在接口上加上@Mapper注解,或在启动类上添加@MapperScan("mapper接口所在路径")
因为使用的是MyBatis-Plus,所以直接继承BaseMapper<实体类名>即可
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
五、编写业务层接口以及实现业务层接口
public interface UserService {
User getUserByName(String name);
}
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wx.springboot_shiro.dao.UserMapper;
import com.wx.springboot_shiro.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author iuxin
* @date create in 20:33 2022/4/16
* @apiNote
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User getUserByName(String name) {
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.eq("name",name);
return userMapper.selectOne(userQueryWrapper);
}
}
六、Controller表现层
@Controller
public class UserController {
@RequestMapping("/testThymeleaf")
public String testThymeleaf(Model model){
model.addAttribute("name","Hello");
return "test";
}
@RequestMapping("/login")
public String login(String name,String password,Model model){
// 使用Shiro编写认证操作
// 1、获取Subject
Subject subject = SecurityUtils.getSubject();
// 2、封装用户数据
UsernamePasswordToken token = new UsernamePasswordToken(name, password);
// 3、执行登录方法
try {
subject.login(token);
// 登录成功跳转到test.html
return "redirect:/testThymeleaf";
}catch (UnknownAccountException e) {
// 登录失败,用户不存在
model.addAttribute("msg","用户不存在");
return "login";
}catch (IncorrectCredentialsException e) {
//登录失败:密码错误
model.addAttribute("msg", "密码错误");
return "login";
}
}
@RequestMapping("/toLogin")
public String toLogin(Model model){
return "login";
}
}
七、shiro包
ShiroConfig类可以进行过滤
@Configuration
public class ShiroConfig {
/**
* 配置ShiroDialect,用于thymeleaf和shiro标签配合使用
* @return
*/
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(
@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 添加Shiro内置过滤器
/**
* Shiro内置过滤器,可以实现权限相关的拦截器
* 常用的过滤器
* anon::无需认证(登录)可以访问
* authc:必须认证才可以访问
* user:如果使用rememberMe的功能可以直接访问
* perms:该资源必须得到资源权限才可以访问
* role:该资源必须得到角色权限才可以访问
*/
Map<String,String> filterMap = new LinkedHashMap<String, String>();
filterMap.put("/testThymeleaf","anon");
filterMap.put("/login","anon");
// 过滤器的授权
filterMap.put("/add","perms[user:add]");
filterMap.put("/**","authc");
// 修改调整的登录页面
shiroFilterFactoryBean.setLoginUrl("/toLogin");
// 设置未授权提示页面
shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 关联realm
securityManager.setRealm(userRealm);
return securityManager;
}
@Bean(name = "userRealm")
public UserRealm getRealm(){
return new UserRealm();
}
}
UserRealm类继承AuthorizingRealm 并重写它的两个方法,一个是授权逻辑,一个是认证逻辑。
再将Servive业务层注入。
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userRealm;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行授权逻辑");
// 给资源进行授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 添加资源的授权字符串
info.addStringPermission("user:add");
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行认证逻辑");
// 填写Shiro判断逻辑 判断用户名和密码
// 1、判断用户名
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
User userByName = userRealm.getUserByName(token.getUsername());
if(userByName == null){
// 用户名不存在
return null; // Shiro底层会抛出UNKnowAccountException
}
// 2、判断密码
return new SimpleAuthenticationInfo("",userByName.getPassword(),"");
}
}
八、在recources包下的templates包内创建两个HTML页面
整个项目结构
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<h3>登录</h3>
<form method="post" action="login">
用户名:<input type="text" name="name" /><br/>
密码:<input type="password" name="password" /><br/>
<input type="submit" value="登录" />
</form>
</body>
</html>
test.html
<!DOCTYPE html>
<html lang="en" xmlns:shiro="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>thymeleaf</title>
</head>
<body>
<h1 th:text="${name}"></h1>
<hr/>
<div shiro:hasPermission="user:add">
进入用户添加功能:<a href="add">用户添加</a>
</div>
<a href="toLogin">登录</a>
</body>
</html>