1、创建springboot工程
2、引入依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.aaa</groupId>
<artifactId>springboot-shiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-shiro</name>
<description>springboot-shiro</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.12.RELEASE</spring-boot.version>
</properties>
<dependencies>
<!--shiro和redis整合的依赖-->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>3.3.1</version>
</dependency>
<!--shrio和thymeleaf集成的扩展依赖,为了能在页面上使用xsln:shrio的标签 -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--shiro和springboot整合的依赖-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.aaa.SpringbootShiroApplication</mainClass>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
3、修改qpplication配置文件
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql:///db3_25?serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
# 日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
mybatis-plus.mapper-locations=classpath:/mapper/*.xml
# thymeleaf 视图解析器
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
# 定义shiro的加密算法
shiro.hashAlgorithmName=MD5
shiro.hashIterations=1024
4、编写实体类和Dao层
实体类
package com.aaa.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
@Data
public class Permission {
@TableId(type = IdType.AUTO)
private Integer id;
private String pername;
private String percode;
}
-------------------------------------------------------------
package com.aaa.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
@Data
public class User {
//名字主键就叫id可以不加此注解
@TableId(type = IdType.AUTO)
private Integer id;
private String username;
private String userpwd;
private String sex;
private String address;
private String salt;
}
5、Dao层
package com.aaa.dao;
import com.aaa.pojo.Permission;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface PermissionDao extends BaseMapper<Permission> {
List<Permission> findUserid(Integer userid);
}
----------------------------------------------------------
package com.aaa.dao;
import com.aaa.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserDao extends BaseMapper<User> {
}
6、编写realm层
package com.aaa.realm;
import com.aaa.pojo.Permission;
import com.aaa.pojo.User;
import com.aaa.service.PermissionService;
import com.aaa.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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.apache.shiro.util.ByteSource;
import org.apache.shiro.util.SimpleByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Autowired
private PermissionService permissionService;
//授权功能
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
User primaryPrincipal = (User) principalCollection.getPrimaryPrincipal();
List<String> permission = permissionService.selectPermissionById(primaryPrincipal.getId());
System.out.println(permission);
if (permission != null) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermissions(permission);
return info;
}
return null;
}
//认证功能
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取登录账号
String username = token.getPrincipal().toString();
//根据账号获取用户信息
User user = userService.findByUsername(username);
System.out.println(user);
if (user != null) {
ByteSource byteSource = new SimpleByteSource(user.getSalt());
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user,user.getUserpwd(),byteSource,this.getName());
return simpleAuthenticationInfo;
}
return null;
}
}
7、编写Service层
权限
package com.aaa.service;
import com.aaa.pojo.Permission;
import java.util.List;
public interface PermissionService {
public List<String> selectPermissionById(Integer userid);
}
package com.aaa.service.Impl;
import com.aaa.dao.PermissionDao;
import com.aaa.pojo.Permission;
import com.aaa.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class PermissionServiceImpl implements PermissionService {
@Autowired
private PermissionDao permissionDao;
@Override
public List<String> selectPermissionById(Integer userid) {
List<Permission> userid1 = permissionDao.findUserid(userid);
List<String> collect = userid1.stream().map(Permission::getPercode).collect(Collectors.toList());
return collect;
}
}
用户
package com.aaa.service;
import com.aaa.pojo.User;
public interface UserService {
public User findByUsername(String username);
}
package com.aaa.service.Impl;
import com.aaa.dao.UserDao;
import com.aaa.pojo.User;
import com.aaa.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public User findByUsername(String username) {
QueryWrapper<User> query = new QueryWrapper<>();
query.eq("username", username);
User user = userDao.selectOne(query);
return user;
}
}
8、编写Controller层
登录
package com.aaa.controller;
import com.aaa.vo.LoginVo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
public class LoginController {
@PostMapping("/login")
public String login( LoginVo loginVo){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(loginVo.getUsername(), loginVo.getPassword());
try {
subject.login(token);
System.out.println("登录成功");
return "success";
}catch (Exception e){
System.out.println("登录失败");
return "redirect:/login,html";
}
}
}
权限层(用户具有什么权限)
package com.aaa.controller;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/query")
@RequiresPermissions(value = "user:query")
public String query(){
return "user:query------------------------";
}
@GetMapping("/update")
@RequiresPermissions(value = "user:update")
public String update(){
return "user:update------------------------";
}
@GetMapping("/delete")
@RequiresPermissions(value = "user:delete")
public String delete(){
return "user:delete------------------------";
}
@GetMapping("/insert")
@RequiresPermissions(value = "user:insert")
public String insert(){
return "user:insert------------------------";
}
@GetMapping("/export")
@RequiresPermissions(value = "user:export")
public String export(){
return "user:export------------------------";
}
}
9、mapper层
<?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">
<!--namesapce的内容必须和对应的接口路径映射-->
<mapper namespace="com.aaa.dao.PermissionDao">
<select id="findUserid" resultType="com.aaa.pojo.Permission">
select p.* from user_role ur join role_permission rp on ur.roleid = rp.roleid
join permission p on p.id = rp.perid where ur.userid = #{userid}
</select>
</mapper>
10、编写shiro的配置类-------特别注意
package com.aaa.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.aaa.filter.LoginFilter;
import com.aaa.realm.MyRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;
import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
@Bean
public DefaultWebSecurityManager securityManager(){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
securityManager.setRealm(myRealm());
securityManager.setCacheManager(redisCacheManager());
return securityManager;
}
@Bean
public RedisCacheManager redisCacheManager(){
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager());
return redisCacheManager;
}
@Bean
public RedisManager redisManager(){
RedisManager redisManager = new RedisManager();
redisManager.setHost("192.168.253.129:6379");
redisManager.setDatabase(1);
return redisManager;
}
@Bean
public MyRealm myRealm(){
MyRealm myRealm=new MyRealm();
//设置密码加密器
myRealm.setCredentialsMatcher(credentialsMatcher());
return myRealm;
}
@Value("${shiro.hashAlgorithmName}")
private String hashAlgorithmName;
@Value("${shiro.hashIterations}")
private int hashIterations;
@Bean
public HashedCredentialsMatcher credentialsMatcher(){
HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName(hashAlgorithmName);
credentialsMatcher.setHashIterations(hashIterations);
return credentialsMatcher;
}
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean factoryBean(){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager());
shiroFilterFactoryBean.setLoginUrl("/login.html");
//设置过滤规则
Map<String,String> map=new HashMap<>();
map.put("/login","anon");
map.put("/**","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
//springboot如何注册web三大组件。
@Bean
public FilterRegistrationBean<Filter> filterRegistrationBean(){
FilterRegistrationBean<Filter> filterRegistrationBean=new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(new DelegatingFilterProxy());
filterRegistrationBean.setName("shiroFilter");
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
/**
* 这里是为了能在html页面引用shiro标签,
*/
@Bean(name = "shiroDialect")
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
}
11、前端页面
登录页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login" method="post">
账号:<input type="text" name="username"><br><br>
密码:<input type="text" name="password"><br><br>
<input type="submit" name="登录"/>
</form>
</body>
</html>
登录成功页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
登录成功页面-------------------
<h1 shiro:hasPermission="user:query">
<a href="/user/query">查询用户</a><br>
</h1>
<h1 shiro:hasPermission="user:update">
<a href="/user/update">修改用户</a><br>
</h1>
<h1 shiro:hasPermission="user:delete">
<a href="/user/delete">删除用户</a><br>
</h1>
<h1 shiro:hasPermission="user:insert">
<a href="/user/insert">添加用户</a><br>
</h1>
<h1 shiro:hasPermission="user:export">
<a href="/user/export">导出用户</a><br>
</h1>
</body>
</html>