Bootstrap

springboot2.6.13整合shiro jwt例子

参考这边文章:
https://blog.csdn.net/Katharsis_2021/article/details/133838688
数据库也是用的若依的基本数据库,ruoyi.vip
1、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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.rainpet</groupId>
    <artifactId>spring-shiro01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-shiro02</name>
    <description>spring-shiro02</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.6.13</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--mybatis plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.23</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-actuator-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.8.2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
            <version>2.12.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.17</version>
        </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.rainpet.springshiro01.SpringShiro01Application</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

2、配置文件:application.yml

server:
  port: 8086

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/mall?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: guest
    password: 369258
    type: com.alibaba.druid.pool.DruidDataSource
  thymeleaf:
    check-template: false
    check-template-location: false
  redis:
    host: 127.0.0.1
    port: 6379
    password: myoa888
    database: 0
    timeout: 30000
    lettuce:
      pool:
        max-active: 100
        max-idle: 10
        min-idle: 5
  web:
    resources:
      add-mappings: false
#  devtools:
#    restart:
#      enabled: true
#      additional-paths: src/main/java
#      exclude: static/**
#    livereload:
#      enabled: true
#      port: 35729


management:
  endpoints:
    web:
      exposure:
        include: beans

mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.rainpet.spring-shiro01.entity
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

logging:
  level:
    root: debug

3、ShiroConfig.java

package com.rainpet.springshiro01.config;

import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;

@Configuration
@ComponentScan(value = "com.rainpet.springshiro01")
public class ShiroConfig {
    // 1.shiroFilter:负责拦截所有请求
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager) {

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 给filter设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        // 默认认证界面路径---当认证不通过时跳转
        shiroFilterFactoryBean.setLoginUrl("/user/login");

        // 添加自己的过滤器并且取名为jwt
        Map<String, Filter> filterMap = new HashMap<>();
        filterMap.put("jwt", new JwtFilter());
        shiroFilterFactoryBean.setFilters(filterMap);

        // 配置系统受限资源
        Map<String, String> map = new HashMap<String, String>();
        map.put("/user/login","anon");
        map.put("/user/register","anon");
        map.put("/login","anon");
        map.put("/**", "jwt");
        // 所有请求通过我们自己的过滤器
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);

        return shiroFilterFactoryBean;
    }

    //2.创建安全管理器
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm realm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 给安全管理器设置realm
        securityManager.setRealm(realm);
        // 关闭shiro的session(无状态的方式使用shiro)
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);
        return securityManager;
    }
}

4、LoginService.java

package com.rainpet.springshiro01.service;

import com.rainpet.springshiro01.entity.SysUser;
import com.rainpet.springshiro01.utils.ResponseResult;

public interface LoginService {
    ResponseResult login(SysUser user);

    ResponseResult logout();
}

5、LoginServiceImpl.java

package com.rainpet.springshiro01.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rainpet.springshiro01.entity.SysUser;
import com.rainpet.springshiro01.mapper.SysUserMapper;
import com.rainpet.springshiro01.service.LoginService;
import com.rainpet.springshiro01.utils.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private RedisUtil redisCache;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Override
    public ResponseResult login(SysUser user) {
        //获取userid和password
        String username = user.getUserName();
        String password = user.getPassword();

        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name", username);

        SysUser loginUser = sysUserMapper.selectOne(queryWrapper);
        if(null == loginUser){
            //throw new RuntimeException("用户名或密码错误");
            return ResponseResult.fail(HttpStatusEnum.BAD_REQUEST,"用户名错误!");
        }
        String userId = loginUser.getUserId().toString();
        String pwd = loginUser.getPassword();

        if(!BcryptUtil.match(password,pwd)){
            //throw new RuntimeException("用户名或密码错误");
            return ResponseResult.fail(HttpStatusEnum.UNAUTHORIZED,"用户名或密码错误!");
        }

        //使用userid生成token
        String jwt = jwtUtil.createJwtToken(userId,36000L);
        //authenticate存入redis
        redisCache.setCacheObject("token_"+jwt,loginUser,36000, TimeUnit.SECONDS);
        //把token响应给前端
        HashMap<String,String> map = new HashMap<>();
        map.put("token",jwt);
        return ResponseResult.success(map);
    }

    @Override
    public ResponseResult logout() {
        return ResponseResult.success("退出成功");
    }
}



6、LoginController.java

package com.rainpet.springshiro01.controller;

import com.rainpet.springshiro01.entity.SysUser;
import com.rainpet.springshiro01.service.impl.LoginServiceImpl;
import com.rainpet.springshiro01.utils.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
@RequestMapping("/")
public class LoginController {

    @Autowired
    LoginServiceImpl loginServiceImpl;
    @PostMapping("/user/login")
    public ResponseResult login(@RequestBody SysUser user){
        return loginServiceImpl.login(user);
    }

    @PostMapping("/hello")
    public ResponseResult hello(){
        return ResponseResult.success("hello");
    }

}

7、SysMenuMapper.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.rainpet.springsecurity.mapper.SysMenuMapper">


    <select id="selectPermsByUserId" resultType="java.lang.String">
        SELECT
            DISTINCT (case when m.`perms`='' then `path` else m.`perms` end)
        FROM
            sys_user_role ur
                LEFT JOIN `sys_role` r ON ur.`role_id` = r.`role_id`
                LEFT JOIN `sys_role_menu` rm ON ur.`role_id` = rm.`role_id`
                LEFT JOIN `sys_menu` m ON m.`menu_id` = rm.`menu_id`
        WHERE
            user_id = #{userid}
    </select>
</mapper>

;