SpringSecurity+jwt+图片验证码,无Bug拿走不谢!

我对你最大的帮助是给你一份无bug的代码,然后你自己去研究

一、pom.xml

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--kaptcha依赖:谷歌的图片验证码生成器-->
        <dependency>
            <groupId>com.github.axet</groupId>
            <artifactId>kaptcha</artifactId>
            <version>0.0.9</version>
        </dependency>
        <!--redis依赖:图片验证码需要用到一个缓存操作-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.18.1</version>
        </dependency>
        <!--Jwt依赖-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.15.0</version>
        </dependency>
        <!-- hutool工具类-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.3</version>
        </dependency>
    </dependencies>

二、数据库连接(application.properties)

server.port=8081
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/privateblog?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
#开启后,hibernate会自动删除数据库数据(没有定义要插入的数据都会被删除)和更新数据库(同步实体类)
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
spring.jpa.properties.hibernate.format_sql=true

三、创建实体类,orm用的springdatajpa,创建实体类即可同步到数据库

1.用户实体类(Sys_user.java)

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;

import static javax.persistence.FetchType.EAGER;
import static javax.persistence.GenerationType.AUTO;

/**
 * 用户实体类
 * @Author losen
 * @Date 2022/10/21 14:08
 * @Version 1.0
 */

@Entity @Data @NoArgsConstructor @AllArgsConstructor
public class Sys_user {
    @Id @GeneratedValue(strategy = AUTO)
    private Long id; // id
    private String nickName; // 昵称
    private String userName; // 用户名
    private String passWord; // 密码
    private String email; // 邮箱
    private Date createdTime; // 创建时间
    private String city; // 城市
    private int status; // 帐号状态
    private Date updatedTime; // 修改时间
    private Date lastLogin; // 最后一次登录时间
    @ManyToMany(fetch = EAGER)
    private Collection<Sys_role> roles = new ArrayList<>(); // 角色集合:多对多
}

2.角色实体类(Sys_role.java)

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;


import static javax.persistence.GenerationType.AUTO;

/**
 * 角色实体类
 * @author losen
 * @date 2022/10/21 14:09
 * @version 1.0
 */

@Entity @Data @NoArgsConstructor @AllArgsConstructor
public class Sys_role {
    @Id
    @GeneratedValue(strategy = AUTO)
    private Long id; // id
    private String name; // 角色名称
    private String remark; //角色备注
    private int status; // 角色状态
}

四、创建mapper类

1.用户类数据库映射类(Sys_userRepo.java)

import com.doll.privateblog.domain.Sys_user;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * 操作用户映射
 * @Author losen
 * @Date 2022/10/21 14:25
 * @Version 1.0
 */
public interface Sys_userRepo extends JpaRepository<Sys_user,Long> {
    /**
     * 根据用户名查询用户
     * @param userName
     * @return
     */
    Sys_user findByUserName(String userName);

    /**
     * 根据用户名删除用户
     * @param userName
     * @return
     */
    Integer deleteSys_userByUserName(String userName);
}

2.角色实体类数据库映射类(Sys_roleRepo.java)

import com.doll.privateblog.domain.Sys_role;
import org.springframework.data.jpa.repository.JpaRepository;


/**
 * 操作角色映射
 * @Author losen
 * @Date 2022/10/21 14:29
 * @Version 1.0
 */
public interface Sys_roleRepo extends JpaRepository<Sys_role,Long> {
    /**
     * 根据用户名查询角色
     * @param name
     * @return
     */
    Sys_role findByName(String name);
}

五、创建接口类

1.用户接口类(Sys_userService.java)

import com.doll.privateblog.domain.Sys_role;
import com.doll.privateblog.domain.Sys_user;

import java.util.List;

/**
 * 用户接口类
 * @Author losen
 * @Date 2022/10/21 14:32
 * @Version 1.0
 */
public interface Sys_userService {

    Sys_user saveUser(Sys_user user);    //添加用户

    Sys_role saveRole(Sys_role role);    //添加角色

    void addRoleToUser(String userName,String roleName);    //给用户添加角色

    Sys_user getUser(String userName);    //根据用户名获取单个用户对象

    List<Sys_user> getUsers();    //获取多个用户对象

    Integer removeByUserName(String userName);     // 根据用户名删除用户
}

六、创建实现类

1.用户接口实现类()

import com.doll.privateblog.domain.Sys_role;
import com.doll.privateblog.domain.Sys_user;
import com.doll.privateblog.repo.Sys_roleRepo;
import com.doll.privateblog.repo.Sys_userRepo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 用户接口实现类
 * @Author losen
 * @Date 2022/10/21 14:40
 * @Version 1.0
 */

@Service @RequiredArgsConstructor @Transactional @Slf4j
public class Sys_userServiceImpl implements Sys_userService, UserDetailsService {
    private final Sys_userRepo userRepo;
    private final Sys_roleRepo roleRepo;
    private final PasswordEncoder passwordEncoder;

    /**
     * 重写登录验证逻辑
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Sys_user user = userRepo.findByUserName(username);
        if(user == null){
            log.error("User not found in the database");
            throw new UsernameNotFoundException("User not found in the database");
        }else {
            log.info("User found in the database : {}", username);
        }
        Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
        user.getRoles().forEach(role -> {
            authorities.add(new SimpleGrantedAuthority(role.getName()));
        });
        return new org.springframework.security.core.userdetails.User(user.getUserName(),user.getPassWord(),authorities);
    }

    /**
     * 新增用户
     * @param user
     * @return
     */
    @Override
    public Sys_user saveUser(Sys_user user) {
        log.info("Saving new user {} to the database", user.getUserName());
        user.setPassWord(passwordEncoder.encode(user.getPassWord()));
        return userRepo.save(user);
    }

    /**
     * 新增角色
     * @param role
     * @return
     */
    @Override
    public Sys_role saveRole(Sys_role role) {
        log.info("Saving new role {} to the database", role.getName());
        return roleRepo.save(role);
    }

    /**
     * 给用户添加角色
     * @param userName
     * @param roleName
     */
    @Override
    public void addRoleToUser(String userName, String roleName) {
        log.info("Adding role {} to user {}", roleName,userName);
        Sys_user user = userRepo.findByUserName(userName);
        Sys_role role = roleRepo.findByName(roleName);
        user.getRoles().add(role);
    }

    /**
     * 根据用户名获取用户对象
     * @param userName
     * @return
     */
    @Override
    public Sys_user getUser(String userName) {
        log.info("Fetching user {}",userName);
        return userRepo.findByUserName(userName);
    }

    /**
     * 获取所有用户对象
     * @return
     */
    @Override
    public List<Sys_user> getUsers() {
        log.info("Fetching all user");
        return userRepo.findAll();
    }

    /**
     * 根据用户名删除用户
     * @param userName
     * @return
     */
    @Override
    public Integer removeByUserName(String userName) {
        return userRepo.deleteSys_userByUserName(userName);
    }
}

七、初始化数据库数据

1.启动类中(application.java)

import com.doll.privateblog.domain.Sys_role;
import com.doll.privateblog.domain.Sys_user;
import com.doll.privateblog.service.Sys_userService;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.ArrayList;

/**
 * 服务模块启动类
 * @author losen
 * @Date 21/10/2022
 * @since 1.0
 */

@SpringBootApplication
public class PrivateBlogServerApplication {
    public static void main(String [] args){
        SpringApplication.run(PrivateBlogServerApplication.class,args);
    }

    /**
     * 注册密码加密Bean
     * @return
     */
    @Bean
    PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }


    /**
     * 初始化数据库
     */
    @Bean
    CommandLineRunner run(Sys_userService userService){
        return args -> {
            userService.saveRole(new Sys_role(null,"ROLE_USER","普通用户",0));
            userService.saveRole(new Sys_role(null,"ROLE_MANAGER","管理员",0));
            userService.saveRole(new Sys_role(null,"ROLE_ADMIN","ADMIN",0));
            userService.saveRole(new Sys_role(null,"ROLE_SUPER_ADMIN","超级管理员",0));


            userService.saveUser(new Sys_user(null,"losen","2375731426","123456","doll9946163@163.com",null,"深圳",0,null,null,new ArrayList<>()));
            userService.saveUser(new Sys_user(null,"losen2","2375731425","123456","doll9946163@163.com",null,"上海",0,null,null,new ArrayList<>()));
            userService.saveUser(new Sys_user(null,"losen3","2375731424","123456","doll9946163@163.com",null,"重庆",0,null,null,new ArrayList<>()));
            userService.saveUser(new Sys_user(null,"losen4","2375731426","123456","doll9946163@163.com",null,"北京",0,null,null,new ArrayList<>()));

            userService.addRoleToUser("2375731426","ROLE_SUPER_ADMIN");
            userService.addRoleToUser("2375731425","ROLE_ADMIN");
            userService.addRoleToUser("2375731424","ROLE_MANAGER");
            userService.addRoleToUser("2375731423","ROLE_USER");
        };
    }
}

八、创建控制层(Controller)

1.Sys_userResource.java

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.doll.privateblog.domain.Sys_role;
import com.doll.privateblog.domain.Sys_user;
import com.doll.privateblog.service.Sys_userService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.util.*;
import java.util.stream.Collectors;
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;

/**
 * 用户接口类
 * @Author losen
 * @Date 2022/10/21 14:54
 * @Version 1.0
 */

@RestController @RequestMapping("/api") @RequiredArgsConstructor @CrossOrigin(origins = "*")
public class Sys_userResource {
    @Autowired
    private Sys_userService sysUserService;

    /**
     * 获取所有用户对象
     * @return
     */
    @GetMapping("/users")
    public ResponseEntity<List<Sys_user>>getUsers(){
        return ResponseEntity.ok().body(sysUserService.getUsers());
    }

    /**
     * 根据用户名获取用户对象
     * @param sysUser
     * @return
     */
    @GetMapping("/user")
    public ResponseEntity<Sys_user>getUser(@RequestParam Sys_user sysUser){
        return ResponseEntity.ok().body(sysUserService.getUser(sysUser.getUserName()));
    }

    /**
     * 新增角色
     * @param username
     * @param password
     * @return
     */
    @SneakyThrows
    @PostMapping("/user/save")
    //  字符串接受主要是,前端要传递图片验证码的key回来与redis中key匹配,如果出现与实体对象不符的属性会出现对象转换异常
    public Map<String,String>saveUser(String username,String password){
        Sys_user sysUser = new Sys_user();
        sysUser.setUserName(username);
        sysUser.setPassWord(password);
        URI uri = URI.create(ServletUriComponentsBuilder.fromCurrentContextPath().path("/api/user/save").toUriString());
        Sys_user user = sysUserService.getUser(sysUser.getUserName());
        Map<String,String> resultMap = new HashMap<>();
        if(user == null){   // 判断该用户名是否存在
            sysUserService.saveUser(sysUser);
            sysUserService.addRoleToUser(username,"ROLE_MANAGER");      //添加的用户初始角色都为ROLE_MANAGER
            resultMap.put("status","200");     // 不存在就可以进行save操作
        }else{
            resultMap.put("status","500");    // 返回500状态值
        }
        return resultMap;
    }

    /**
     * 新增角色
     * @param role
     * @return
     */
    @PostMapping("/role/save")
    public ResponseEntity<Sys_role>saveRole(@RequestBody Sys_role role){
        URI uri = URI.create(ServletUriComponentsBuilder.fromCurrentContextPath().path("/api/role/save").toUriString());
        return ResponseEntity.created(uri).body(sysUserService.saveRole(role));
    }

    /**
     * 给用户添加角色
     * @param form
     * @return
     */
    @PostMapping("/role/addtouser")
    public ResponseEntity<?>addRoleToUser(@RequestBody RoleToUserForm form){
        sysUserService.addRoleToUser(form.getUsername(), form.getRoleName());
        return ResponseEntity.ok().build();
    }

    /**
     * 刷新token,jwt刷新token的方式是:前端登录成功后后端创建token返回给前端,刷新token需要前端携带refresh_token,可以在跳转页面时刷新token
     * @param request
     * @param response
     * @throws IOException
     */
    @GetMapping("/token/refresh")
    public void refreshToken(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Map<String,Object> tokens = new HashMap<>();
        String authorizationHeader = request.getHeader(AUTHORIZATION);
        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            try {
                String refresh_token = authorizationHeader.substring("Bearer ".length());
                Algorithm algorithm = Algorithm.HMAC256("secret".getBytes());
                JWTVerifier verifier = JWT.require(algorithm).build();
                DecodedJWT decodedJWT = verifier.verify(refresh_token);
                String username = decodedJWT.getSubject();
                Sys_user user = sysUserService.getUser(username);
                //  获取用户角色,让前端判断该角色是否可以进入该页面
                List<String> collect = user.getRoles().stream().map(Sys_role::getName).collect(Collectors.toList());
                String access_token = JWT.create()
                        . withSubject(user.getUserName())
                        .withExpiresAt(new Date(System.currentTimeMillis()+10*60*1000))
                        .withIssuer(request.getRequestURI().toString())
                        .withClaim("roles",user.getRoles().stream().map(Sys_role::getName).collect(Collectors.toList()))
                        .sign(algorithm);
                tokens.put("access_token",access_token);
                tokens.put("refresh_token",refresh_token);
                tokens.put("status","200");
                tokens.put("roles",collect);    // 返回角色信息
                response.setContentType(APPLICATION_JSON_VALUE);
                new ObjectMapper().writeValue(response.getOutputStream(),tokens);
            }catch (Exception exception){
                response.setHeader("error",exception.getMessage());
                Map<String,String> error = new HashMap<>();
                error.put("error_message",exception.getMessage());
                response.setContentType(APPLICATION_JSON_VALUE);
                tokens.put("status","500");
                new ObjectMapper().writeValue(response.getOutputStream(),tokens);
            }
        }else {
            tokens.put("status","500");
            new ObjectMapper().writeValue(response.getOutputStream(),tokens);
            throw new RuntimeException("Refresh token is missing");
        }
    }

    @GetMapping("/user/delete")
    public Map<String,String>addRoleToUser(String userName){
        Map<String,String> resultMap= new HashMap<>();
        sysUserService.removeByUserName(userName);
        resultMap.put("status","200");
        return resultMap;
    }
}

@Data
class RoleToUserForm{
    private String username;
    private String roleName;
}

2.图片验证码控制器(CaptchaResource.java)

import cn.hutool.core.lang.UUID;

import com.doll.privateblog.domain.Const;
import com.doll.privateblog.utils.RedisUtil;
import com.google.code.kaptcha.Producer;
import lombok.RequiredArgsConstructor;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


/**
 * 图片验证码接口
 * @author losen
 * @version 1.0
 * @DateTime 2022/10/22 14:36
 */

@RestController @RequestMapping("/api") @RequiredArgsConstructor
public class CaptchaResource {
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    Producer producer;

    @GetMapping("/captcha")
    public Map<String,Object> Captcha(HttpServletResponse response) throws IOException {

        String key = UUID.randomUUID().toString();
        String code = producer.createText();

        BufferedImage image = producer.createImage(code);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(image,"png",outputStream);
        byte[] imageByte = outputStream.toByteArray();

        String str = "data:image/png;base64,";

//        String base64Img = str + encoder.encode(outputStream.toByteArray());

        redisUtil.hset("captcha", key, code, 120);

        Base64 base64 = new Base64();
        Map<String,Object> captchaMap = new HashMap<>();
        captchaMap.put("image",base64.encodeToString(imageByte));
        captchaMap.put("uuid",key);
        return captchaMap;
    }
}

九、创建配置类和工具类

1.跨域配置类(CorsConfig.java)

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import java.util.ArrayList;
import java.util.List;

/**
 * 跨域配置类
 * @author losen
 * @date 2022/10/22 14:31
 * @since 1.0.0
 */

@Configuration
public class CorsConfig {
    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);  //sessionid 多次访问一致

        // 允许访问的客户端域名
        List<String> allowedOriginPatterns = new ArrayList<>();
        allowedOriginPatterns.add("*");
        corsConfiguration.setAllowedOriginPatterns(allowedOriginPatterns);
        corsConfiguration.addAllowedOriginPattern("*"); // 允许任何域名使用
        corsConfiguration.addAllowedHeader("*"); // 允许任何头
        corsConfiguration.addAllowedMethod("*"); // 允许任何方法(post、get等)
        return corsConfiguration;
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig()); // 对接口配置跨域设置
        return new CorsFilter(source);
    }
}

2.过滤器配置类(SecurityConfig.java)

import com.doll.privateblog.filter.CustomAuthenticationFilter;
import com.doll.privateblog.filter.CustomAuthorizationFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.HttpMethod.POST;
import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS;


/**
 * 过滤器配置器
 * @Author losen
 * @Date 2022/10/21 16:21
 * @Version 1.0
 */

@Configuration @EnableWebSecurity @RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private final UserDetailsService userDetailsService;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;
    private final CaptchaFilter captchaFilter;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
    }


    @Override
    protected void configure(HttpSecurity http)throws Exception{
        CustomAuthenticationFilter customAuthenticationFilter = new CustomAuthenticationFilter(authenticationManagerBean());
        customAuthenticationFilter.setFilterProcessesUrl("/api/login");
        http.sessionManagement().sessionCreationPolicy(STATELESS);
        http.authorizeRequests().antMatchers("/api/captcha","/api/user/save","/api/login/**","/api/token/refresh/**","/api/makeLineAndShapeChart","/api/users").permitAll();   // 设置不用拦截的api
//        http.authorizeRequests().antMatchers(GET,"/api/user/**").hasAnyAuthority("ROLE_USER");
//        http.authorizeRequests().antMatchers(POST,"/api/user/save/**").hasAnyAuthority("ROLE_ADMIN");
        http.authorizeRequests().anyRequest().authenticated();
        http.addFilter(customAuthenticationFilter);
        http.addFilter(customAuthenticationFilter);


        http.addFilterBefore(new CustomAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
        http.addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class);    // 添加验证码拦截校验过滤器
        http.cors().and().csrf().disable();     // 关闭cors和csrf(防止跨域伪造攻击)
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

3.图片验证码样式配置类(KaptchaConfig.java)

import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Properties;

/**
 * 验证码图片样式配置
 * @author losen
 * @date 2022/10/22 13:43
 * @since 1.0.0
 */
@Configuration
public class KaptchaConfig {

    @Bean
    DefaultKaptcha producer(){
        Properties properties = new Properties();
        properties.put("kaptcha.border","no");
        properties.put("kaptcha.textproducer.font.color","black");
        properties.put("kaptcha.textproducer.char.space","4");
        properties.put("kaptcha.image.height","40");
        properties.put("kaptcha.image.width","120");
        properties.put("kaptcha.textproducer.font.size","30");

        Config config = new Config(properties);
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        defaultKaptcha.setConfig(config);

        return defaultKaptcha;

    }
}

4.图片验证码内容配置类(CaptchaUtil.java)

import cn.hutool.core.codec.Base64;
import lombok.extern.slf4j.Slf4j;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Random;

/**
 * 图片验证码内容配置类
 * @author losen
 * @version 1.0
 * @DateTime 2022/10/24 13:39
 */

@Slf4j
public class CaptchaUtil {
    //验证码个数
    private int count=4;
    //验证码宽度,且设置每个字的宽度
    private int width=count*50;
    //验证码高度
    private int height=50;
    //图片验证码key
    private String code="";
    //bufferedImage
    private BufferedImage bufferedImage;
    public CaptchaUtil() {
    }
    public CaptchaUtil(int count, int width, int height) {
        this.count = count;
        this.width = width;
        this.height = height;
    }
    public int getCount() {
        return count;
    }
    public String getCode() {
        return code;
    }
    public int getWidth() {
        return width;
    }
    public int getHeight() {
        return height;
    }
    public void setCount(int count) {
        this.count = count;
        width=this.count*50;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public void setHeight(int height) {
        this.height = height;
    }
    //测试写入
    public static void main(String[] args){
        long startend=System.currentTimeMillis();
        CaptchaUtil captchaUtil =new CaptchaUtil();
        //默认验证码位数为4,我这里设为5
        captchaUtil.setCount(5);
        //得到缓冲区
        BufferedImage image = captchaUtil.getImage();
        //得到真实验证码
        String code= captchaUtil.getCode();
        long endTime=System.currentTimeMillis();
        System.out.println("验证码为:"+code+"\n花费时间为:"+(endTime-startend)+"\n到E盘根目录下看,文件名为11.jpg");
    }
    public BufferedImage getImage(){
        //图片缓冲区
        BufferedImage image = new BufferedImage(width,height,1);
        //获得笔
        Graphics graphics = image.getGraphics();
        //设置初始画笔为白色
        graphics.setColor(new Color(255,255,254));
        //画满整个图,也就是把图片先变为白色
        graphics.fillRect(0,0,width,height);
        Random rd=new Random();
        //设置字体
        Font font=new Font("宋体",Font.PLAIN,35+rd.nextInt(10));
        graphics.setFont(font);
        char[] chars="qweCRYHrtasdfBxy678934VTGopNUFKuighjklzSXEDLOP12cvbnmQAZWJMI50".toCharArray();
        //画验证码
        for (int i = 0; i <count ; i++) {
            String string="";
            string+=chars[rd.nextInt(chars.length)]+"";
            graphics.setColor(new Color(rd.nextInt(254),rd.nextInt(254),rd.nextInt(254)));
            graphics.drawString(string,55*i+rd.nextInt(10),27+rd.nextInt(15));
            code+=string;
        }
        //干扰点
        for (int i = 0; i <25*count ; i++) {
            graphics.setFont(new Font("宋体",Font.PLAIN,15));
            String string=".";
            graphics.setColor(new Color(rd.nextInt(255),rd.nextInt(255),rd.nextInt(255)));
            graphics.drawString(string,rd.nextInt(width),rd.nextInt(height));
        }
        //干扰线
        for (int i = 0; i <count+count/2 ; i++) {
            graphics.setFont(new Font("宋体",Font.PLAIN,10));
            graphics.setColor(new Color(rd.nextInt(255),rd.nextInt(255),rd.nextInt(255)));
            graphics.drawLine(rd.nextInt(width),rd.nextInt(height),rd.nextInt(width),rd.nextInt(height));
        }
        //归还笔
        graphics.dispose();
        //写到流里面需要用到ImageIo
        //这里做的测试,在本地测试下是否画的是那回事
        /*try {
            ImageIO.write(image,"jpg",new FileOutputStream("E:/11.jpg"));
        } catch (IOException e) {
            e.printStackTrace();
        }*/
        this.bufferedImage=image;
        return image;
    }
    /**
     *  @author: 执着(zlm)
     *  @Date: 2020/9/27 23:37
     *  @Description: 将图片缓冲区转成base64编码
     */
    public static String getBase64(BufferedImage image){
        String base64 = null;
        try {
            //输出流
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            ImageIO.write(image, "png", stream);
            base64 = Base64.encode(stream.toByteArray());
            log.info("生成的图片验证码base64:{}",base64);
        } catch (IOException e) {
            log.error("生成生成的图片验证码base64失败:{}",e.getMessage());
            e.printStackTrace();
        }
        return base64;

    }
}

        

5.Redis工具类(RedisUtil.java)

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Redis工具类
 * @author losen
 * @DateTime  2022/10/22 13:43
 * @since 1.0.0
 */
@RequiredArgsConstructor
@Configuration
public class RedisUtil {
    private final RedisTemplate redisTemplate;
    // =============================common============================
    /**
     * 指定缓存失效时间
     * @param key 键
     * @param time 时间(秒)
     * @return
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 根据key 获取过期时间
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }
    /**
     * 判断key是否存在
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 删除缓存
     * @param key 可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }
    // ============================String=============================
    /**
     * 普通缓存获取
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }
    /**
     * 普通缓存放入
     * @param key 键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 普通缓存放入并设置时间
     * @param key 键
     * @param value 值
     * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 递增
     * @param key 键
     * @param delta 要增加几(大于0)
     * @return
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }
    /**
     * 递减
     * @param key 键
     * @param delta 要减少几(小于0)
     * @return
     */
    public long decr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递减因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }
    // ================================Map=================================
    /**
     * HashGet
     * @param key 键 不能为null
     * @param item 项 不能为null
     * @return 值
     */
    public Object hget(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }
    /**
     * 获取hashKey对应的所有键值
     * @param key 键
     * @return 对应的多个键值
     */
    public Map<Object, Object> hmget(String key) {
        return redisTemplate.opsForHash().entries(key);
    }
    /**
     * HashSet
     * @param key 键
     * @param map 对应多个键值
     * @return true 成功 false 失败
     */
    public boolean hmset(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * HashSet 并设置时间
     * @param key 键
     * @param map 对应多个键值
     * @param time 时间(秒)
     * @return true成功 false失败
     */
    public boolean hmset(String key, Map<String, Object> map, long time) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 向一张hash表中放入数据,如果不存在将创建
     * @param key 键
     * @param item 项
     * @param value 值
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 向一张hash表中放入数据,如果不存在将创建
     * @param key 键
     * @param item 项
     * @param value 值
     * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value, long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 删除hash表中的值
     * @param key 键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    public void hdel(String key, Object... item) {
        redisTemplate.opsForHash().delete(key, item);
    }
    /**
     * 判断hash表中是否有该项的值
     * @param key 键 不能为null
     * @param item 项 不能为null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
        return redisTemplate.opsForHash().hasKey(key, item);
    }
    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     * @param key 键
     * @param item 项
     * @param by 要增加几(大于0)
     * @return
     */
    public double hincr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, by);
    }
    /**
     * hash递减
     * @param key 键
     * @param item 项
     * @param by 要减少记(小于0)
     * @return
     */
    public double hdecr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, -by);
    }
    // ============================set=============================
    /**
     * 根据key获取Set中的所有值
     * @param key 键
     * @return
     */
    public Set<Object> sGet(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 根据value从一个set中查询,是否存在
     * @param key 键
     * @param value 值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value) {
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 将数据放入set缓存
     * @param key 键
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * 将set数据放入缓存
     * @param key 键
     * @param time 时间(秒)
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0) {
                expire(key, time);
            }
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * 获取set缓存的长度
     * @param key 键
     * @return
     */
    public long sGetSetSize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * 移除值为value的
     * @param key 键
     * @param values 值 可以是多个
     * @return 移除的个数
     */
    public long setRemove(String key, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    // ===============================list=================================
    /**
     * 获取list缓存的内容
     * @param key 键
     * @param start 开始
     * @param end 结束 0 到 -1代表所有值
     * @return
     */
    public List<Object> lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 获取list缓存的长度
     * @param key 键
     * @return
     */
    public long lGetListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    /**
     * 通过索引 获取list中的值
     * @param key 键
     * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     * @return
     */
    public Object lGetIndex(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 将list放入缓存
     * @param key 键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 将list放入缓存
     * @param key 键
     * @param value 值
     * @param time 时间(秒)
     * @return
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 将list放入缓存
     * @param key 键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 将list放入缓存
     *
     * @param key 键
     * @param value 值
     * @param time 时间(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 根据索引修改list中的某条数据
     * @param key 键
     * @param index 索引
     * @param value 值
     * @return
     */
    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 移除N个值为value
     * @param key 键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */
    public long lRemove(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
}

6.Redis配置类(RedisConfig.java)

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * Redis配置类
 * @author losen
 * @date 2022/10/22 14:32
 * @since 1.0.0
 */

@Configuration
public class RedisConfig {


    //调整redis序列化方式后写入缓存
    @Bean
    RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        jackson2JsonRedisSerializer.setObjectMapper(new ObjectMapper());

        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        return redisTemplate;
    }
}

十、过滤器(Filter)

1.图片验证码过滤器(CaptchaFilter.java)

import com.doll.privateblog.utils.RedisUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.security.sasl.AuthenticationException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 图片验证码校验过滤器
 * @author losen
 * @DateTime  2022/10/22 13:43
 * @version  1.0
 */

@Slf4j
@RequiredArgsConstructor
@Configuration
public class CaptchaFilter extends OncePerRequestFilter {
    private static final String CAPTCHA_KEY = "captcha";
    private final RedisUtil redisUtil;

    @SneakyThrows
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws AuthenticationException, IOException {
        String url = request.getRequestURI();
        if(("/api/login".equals(url) && request.getMethod().equals("POST")) || ("/api/user/save".equals(url) && request.getMethod().equals("POST"))){     // 如果是登录接口,就要进行拦截-校验-过滤,校验验证码是否正确
            try{    // 如果调用验证码校验方法有错,进行捕获
                validate(request);      // 调用验证码校验方法
            }catch (AuthenticationException e){
                log.error("Verification code failed");
                throw new AuthenticationException(e.getMessage());    // 验证失败,具体错误要到方法内报错信息
            }
        }
        filterChain.doFilter(request,response);     // 拦截-校验-过滤之后,放行
    }

    //校验验证逻辑
    private void validate(HttpServletRequest request) throws AuthenticationException {

        String code = request.getParameter("code");
        String key = request.getParameter("key");
        System.out.println("key:"+key);
        Object hget = redisUtil.hget(CAPTCHA_KEY, key);

        if(code == null || key == null){
            log.error("No verification code is received");  // 没有接收到验证码
            throw new AuthenticationException("No verification code is received");
        }
        if(!code.equals(redisUtil.hget(CAPTCHA_KEY,key))){
            log.error("Verification code error");   // 验证码错误
            throw new AuthenticationException("Verification code error");
        }
        redisUtil.hdel(CAPTCHA_KEY,key);    // 验证正确之后,验证码作废,将redis里的验证码删除,一次性使用
    }
}

2.用户登录过滤器(CustomAuthenticationFilter.java)

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 用户登录校验过滤器
 * @Author losen
 * @Date 2022/10/21 16:43
 * @Version 1.0
 */

@Slf4j
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private static final String APPLICATION_JSON_VALUE = "application/json";
    private final AuthenticationManager authenticationManager;


    public CustomAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @SneakyThrows
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        String name = request.getParameter("username");

        String pwd = request.getParameter("password");

        log.info("Username is: {}", name);
        log.info("password is: {}", pwd);

        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(name,pwd);
        return authenticationManager.authenticate(authenticationToken);
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {
        User user = (User) authentication.getPrincipal();
        Algorithm algorithm = Algorithm.HMAC256("secret".getBytes());
        String access_token = JWT.create()
                .withSubject(user.getUsername())
                .withExpiresAt(new Date(System.currentTimeMillis()+10*60*1000))
                .withIssuer(request.getRequestURI().toString())
                .withClaim("roles",user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
                .sign(algorithm);
        String refresh_token = JWT.create()
                .withSubject(user.getUsername())
                .withExpiresAt(new Date(System.currentTimeMillis()+30*60*1000))
                .withIssuer(request.getRequestURI().toString())
                .sign(algorithm);
//        response.setHeader("access_token",access_token);
//        response.setHeader("refresh_token",refresh_token);
//
        Map<String,String> tokens = new HashMap<>();
        tokens.put("access_token",access_token);
        tokens.put("refresh_token",refresh_token);
        tokens.put("status","200");
        response.setContentType(APPLICATION_JSON_VALUE);

        new ObjectMapper().writeValue(response.getOutputStream(),tokens);
    }
}

3.请求过滤器(CustomAuthorizationFilter.java)

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import static java.util.Arrays.stream;
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;

/**
 *请求过滤器(前端大部分请求都要先在这里校验)
 * @Author losen
 * @Date 2022/10/21 18:51
 * @Version 1.0
 */

@Slf4j
public class CustomAuthorizationFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //除了登录和刷新token请求不用刷新token
        if (request.getServletPath().equals("/api/login") || request.getServletPath().equals("/api/token/refresh")) {
            filterChain.doFilter(request,response);
        }else {
            String authorizationHeader = request.getHeader(AUTHORIZATION);
            if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
                try {
                    String token = authorizationHeader.substring("Bearer ".length());
                    Algorithm algorithm = Algorithm.HMAC256("secret".getBytes());
                    JWTVerifier verifier = JWT.require(algorithm).build();
                    DecodedJWT decodedJWT = verifier.verify(token);
                    String username = decodedJWT.getSubject();
                    String[] roles = decodedJWT.getClaim("roles").asArray(String.class);
                    Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
                    stream(roles).forEach(role -> {
                        authorities.add(new SimpleGrantedAuthority(role));
                    });

                    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username,null,authorities);
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                    filterChain.doFilter(request,response);
                }catch (Exception exception){
                    log.error("Error logging in: {}",exception.getMessage());
                    response.setHeader("error",exception.getMessage());
                    Map<String,String> error = new HashMap<>();
                    error.put("error_message",exception.getMessage());
                    response.setContentType(APPLICATION_JSON_VALUE);
                    new ObjectMapper().writeValue(response.getOutputStream(),error);
                }
            }else {
                filterChain.doFilter(request,response);
            }
        }
    }

}

完毕!!!有问题亲留言!!!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哆le

一分两分也是爱,不求多哈哈哈

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值