CRM项目配置Redis并以集群的形式存储Token登录信息并封装提交到前端------CRM项目

package com.alatus.config.filter;

import com.alatus.constant.Constants;
import com.alatus.model.TUser;
import com.alatus.result.R;
import com.alatus.service.RedisService;
import com.alatus.util.JSONUtils;
import com.alatus.util.JWTUtils;
import com.alatus.util.ResponseUtils;
import com.alatus.result.CodeEnum;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import static com.alatus.result.CodeEnum.TOKEN_IS_EXPIRED;


@Component
public class TokenVerifyFilter extends OncePerRequestFilter {

    @Resource
    private RedisService redisService;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (request.getRequestURI().equals(Constants.LOGIN_URI)) { //如果是登录请求,此时还没有生成jwt,那不需要对登录请求进行jwt验证
            //验证jwt通过了 ,让Filter链继续执行,也就是继续执行下一个Filter
            filterChain.doFilter(request, response);
        } else {
            String token = request.getHeader("Authorization");
            System.out.println(token);
            if(!StringUtils.hasText("Authorization")){
//                没拿到token,将失败这个枚举传回去,解析并取出常量拼接
                R result = R.FAIL(CodeEnum.TOKEN_IS_EMPTY);
//                封装
                String resultJSON = JSONUtils.toJSON(result);
//                返回
                ResponseUtils.write(response,resultJSON);
                return;
            }
//            验证token有没有被篡改过,也是验证token合法性
            if (!(JWTUtils.verifyJWT(token))){
//                token不合法
                R result = R.FAIL(CodeEnum.TOKEN_IS_NONE_MATCH);
//                封装
                String resultJSON = JSONUtils.toJSON(result);
//                返回
                ResponseUtils.write(response,resultJSON);
                return;
            }
            TUser tUser = JWTUtils.parseUserFromJWT(token);
            String redisToken = (String) redisService.getValue(Constants.REDIS_JWT_KEY + tUser.getId());
            if(!StringUtils.hasText(redisToken)){
//                没有获取到内容说明token过期了
                R fail = R.FAIL(TOKEN_IS_EXPIRED.getMsg());
                String json = JSONUtils.toJSON(fail);
                ResponseUtils.write(response,json);
                return;
            }
            if (!redisToken.equals(token)) {
//                登陆失败token错误
                R result = R.FAIL(CodeEnum.TOKEN_IS_ERROR.getMsg());
//                把R对象转为JSON
                String json = JSONUtils.toJSON(result);
                ResponseUtils.write(response,json);
                return;
            }
//            jwt验证通过了
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(tUser,tUser.getLoginPwd(),tUser.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
//            验证jwt通过了,让filter链继续执行
            filterChain.doFilter(request,response);
        }
    }
}
package com.alatus.config.filter;

import com.alatus.constant.Constants;
import com.alatus.model.TUser;
import com.alatus.result.R;
import com.alatus.service.RedisService;
import com.alatus.util.JSONUtils;
import com.alatus.util.JWTUtils;
import com.alatus.util.ResponseUtils;
import com.alatus.result.CodeEnum;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import static com.alatus.result.CodeEnum.TOKEN_IS_EXPIRED;


@Component
public class TokenVerifyFilter extends OncePerRequestFilter {

    @Resource
    private RedisService redisService;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (request.getRequestURI().equals(Constants.LOGIN_URI)) { //如果是登录请求,此时还没有生成jwt,那不需要对登录请求进行jwt验证
            //验证jwt通过了 ,让Filter链继续执行,也就是继续执行下一个Filter
            filterChain.doFilter(request, response);
        } else {
            String token = request.getHeader("Authorization");
            System.out.println(token);
            if(!StringUtils.hasText("Authorization")){
//                没拿到token,将失败这个枚举传回去,解析并取出常量拼接
                R result = R.FAIL(CodeEnum.TOKEN_IS_EMPTY);
//                封装
                String resultJSON = JSONUtils.toJSON(result);
//                返回
                ResponseUtils.write(response,resultJSON);
                return;
            }
//            验证token有没有被篡改过,也是验证token合法性
            if (!(JWTUtils.verifyJWT(token))){
//                token不合法
                R result = R.FAIL(CodeEnum.TOKEN_IS_NONE_MATCH);
//                封装
                String resultJSON = JSONUtils.toJSON(result);
//                返回
                ResponseUtils.write(response,resultJSON);
                return;
            }
            TUser tUser = JWTUtils.parseUserFromJWT(token);
            String redisToken = (String) redisService.getValue(Constants.REDIS_JWT_KEY + tUser.getId());
            if(!StringUtils.hasText(redisToken)){
//                没有获取到内容说明token过期了
                R fail = R.FAIL(TOKEN_IS_EXPIRED.getMsg());
                String json = JSONUtils.toJSON(fail);
                ResponseUtils.write(response,json);
                return;
            }
            if (!redisToken.equals(token)) {
//                登陆失败token错误
                R result = R.FAIL(CodeEnum.TOKEN_IS_ERROR.getMsg());
//                把R对象转为JSON
                String json = JSONUtils.toJSON(result);
                ResponseUtils.write(response,json);
                return;
            }
//            jwt验证通过了
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(tUser,tUser.getLoginPwd(),tUser.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
//            验证jwt通过了,让filter链继续执行
            filterChain.doFilter(request,response);
        }
    }
}
package com.alatus.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig
{
    @Bean
    public RedisTemplate redisTemplate(LettuceConnectionFactory lettuceConnectionFactory){
        RedisTemplate redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}
package com.alatus.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig
{
    @Bean
    public RedisTemplate redisTemplate(LettuceConnectionFactory lettuceConnectionFactory){
        RedisTemplate redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}
package com.alatus.config;

import com.alatus.config.filter.TokenVerifyFilter;
import com.alatus.config.handler.MyAuthenticationFailureHandler;
import com.alatus.config.handler.MyAuthenticationSuccessHandler;
import com.alatus.constant.Constants;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;

@Configuration
public class SecurityConfig {
    @Resource
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

    @Resource
    private TokenVerifyFilter tokenVerifyFilter;
//    配置加密器
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    @Resource
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity,CorsConfigurationSource configurationSource) throws Exception{
        return httpSecurity
                .formLogin((formLogin) -> {
                    formLogin.loginProcessingUrl((Constants.LOGIN_URI))
                            .usernameParameter("loginAct")
                            .passwordParameter("loginPwd")
                            .successHandler(myAuthenticationSuccessHandler)
                            .failureHandler(myAuthenticationFailureHandler);
                })
//        SecurityFilterChain改变了默认行为,不再拦截了,需要手动拦截
                .authorizeHttpRequests((authorize) -> {
//                    对任何请求进行拦截,任何请求都需要登录才可以访问
//                    /api/login这个请求放开,其他请求正常拦截
                    authorize.requestMatchers("/api/login").permitAll().anyRequest().authenticated();
                })
                .csrf((csrf) -> {

                    //禁用跨站请求伪造
                    csrf.disable();
                })
                //支持跨域请求
                .cors((cors)->{
                    cors.configurationSource(configurationSource);
                })
                .sessionManagement((session) -> {
//                    让session的创建策略为不创建
                    session.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
                })
//                添加我们自定义的filter
                .addFilterBefore(tokenVerifyFilter, LogoutFilter.class)
                .build();
    }
    @Bean
    public CorsConfigurationSource configurationSource(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedOrigins(Arrays.asList("*"));//允许任意来源
        corsConfiguration.setAllowedMethods(Arrays.asList("*"));//允许任意方法请求
        corsConfiguration.setAllowedHeaders(Arrays.asList("*"));//允许请求头任意内容
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
//        任何路径都按这个来
        source.registerCorsConfiguration("/**",corsConfiguration);
        return source;
    }
}
package com.alatus.config;

import com.alatus.config.filter.TokenVerifyFilter;
import com.alatus.config.handler.MyAuthenticationFailureHandler;
import com.alatus.config.handler.MyAuthenticationSuccessHandler;
import com.alatus.constant.Constants;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;

@Configuration
public class SecurityConfig {
    @Resource
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

    @Resource
    private TokenVerifyFilter tokenVerifyFilter;
//    配置加密器
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    @Resource
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity,CorsConfigurationSource configurationSource) throws Exception{
        return httpSecurity
                .formLogin((formLogin) -> {
                    formLogin.loginProcessingUrl((Constants.LOGIN_URI))
                            .usernameParameter("loginAct")
                            .passwordParameter("loginPwd")
                            .successHandler(myAuthenticationSuccessHandler)
                            .failureHandler(myAuthenticationFailureHandler);
                })
//        SecurityFilterChain改变了默认行为,不再拦截了,需要手动拦截
                .authorizeHttpRequests((authorize) -> {
//                    对任何请求进行拦截,任何请求都需要登录才可以访问
//                    /api/login这个请求放开,其他请求正常拦截
                    authorize.requestMatchers("/api/login").permitAll().anyRequest().authenticated();
                })
                .csrf((csrf) -> {

                    //禁用跨站请求伪造
                    csrf.disable();
                })
                //支持跨域请求
                .cors((cors)->{
                    cors.configurationSource(configurationSource);
                })
                .sessionManagement((session) -> {
//                    让session的创建策略为不创建
                    session.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
                })
//                添加我们自定义的filter
                .addFilterBefore(tokenVerifyFilter, LogoutFilter.class)
                .build();
    }
    @Bean
    public CorsConfigurationSource configurationSource(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedOrigins(Arrays.asList("*"));//允许任意来源
        corsConfiguration.setAllowedMethods(Arrays.asList("*"));//允许任意方法请求
        corsConfiguration.setAllowedHeaders(Arrays.asList("*"));//允许请求头任意内容
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
//        任何路径都按这个来
        source.registerCorsConfiguration("/**",corsConfiguration);
        return source;
    }
}
package com.alatus.constant;

public class Constants {
    public static final String LOGIN_URI = "/api/login";
//    redis的key命名规范,项目名:模块名:功能名:唯一业务参数(比如用户ID)
    public static final String REDIS_JWT_KEY = "crmSystem:user:login:";
//    七天时间
    public static final Long EXPIRE_TIME = 7 * 24 * 60 * 60L;
//    三十分钟
    public static final Long DEFAULT_EXPIRE_TIME = 30 * 60L;

}
package com.alatus.constant;

public class Constants {
    public static final String LOGIN_URI = "/api/login";
//    redis的key命名规范,项目名:模块名:功能名:唯一业务参数(比如用户ID)
    public static final String REDIS_JWT_KEY = "crmSystem:user:login:";
//    七天时间
    public static final Long EXPIRE_TIME = 7 * 24 * 60 * 60L;
//    三十分钟
    public static final Long DEFAULT_EXPIRE_TIME = 30 * 60L;

}
package com.alatus.result;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum CodeEnum {
    OK(200,"成功"),
    FAIL(500,"失败"),
    TOKEN_IS_EMPTY(901,"请求Token参数为空"),
    TOKEN_IS_EXPIRED(902,"Token已过期"),
    TOKEN_IS_ERROR(903,"Token有误"),
    TOKEN_IS_NONE_MATCH(904,"Token信息不合法");

//    结果码
    private int code;
//    结果信息
    private String msg;
}
package com.alatus.result;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum CodeEnum {
    OK(200,"成功"),
    FAIL(500,"失败"),
    TOKEN_IS_EMPTY(901,"请求Token参数为空"),
    TOKEN_IS_EXPIRED(902,"Token已过期"),
    TOKEN_IS_ERROR(903,"Token有误"),
    TOKEN_IS_NONE_MATCH(904,"Token信息不合法");

//    结果码
    private int code;
//    结果信息
    private String msg;
}
package com.alatus.service;

import java.util.concurrent.TimeUnit;

public interface RedisService {
    void setValue(String key,Object value);
    Object getValue(String key);
    Boolean removeValue(String key);
    Boolean expire(String key, Long timeOut, TimeUnit timeUnit);
}
package com.alatus.service;

import java.util.concurrent.TimeUnit;

public interface RedisService {
    void setValue(String key,Object value);
    Object getValue(String key);
    Boolean removeValue(String key);
    Boolean expire(String key, Long timeOut, TimeUnit timeUnit);
}

 

package com.alatus.service.impl;

import com.alatus.service.RedisService;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class RedisServiceImpl implements RedisService {
//    数据源
    @Resource
    private RedisTemplate redisTemplate;
//        放入数据
    @Override
    public void setValue(String key, Object value) {
        redisTemplate.opsForValue().set(key,value);
    }
//取出数据
    @Override
    public Object getValue(String key) {
        return redisTemplate.opsForValue().get(key);
    }
//删除数据
    @Override
    public Boolean removeValue(String key) {
        return redisTemplate.delete(key);
    }

    @Override
    public Boolean expire(String key, Long timeOut, TimeUnit timeUnit) {
        return redisTemplate.expire(key,timeOut,timeUnit);
    }
}
package com.alatus.service.impl;

import com.alatus.service.RedisService;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class RedisServiceImpl implements RedisService {
//    数据源
    @Resource
    private RedisTemplate redisTemplate;
//        放入数据
    @Override
    public void setValue(String key, Object value) {
        redisTemplate.opsForValue().set(key,value);
    }
//取出数据
    @Override
    public Object getValue(String key) {
        return redisTemplate.opsForValue().get(key);
    }
//删除数据
    @Override
    public Boolean removeValue(String key) {
        return redisTemplate.delete(key);
    }

    @Override
    public Boolean expire(String key, Long timeOut, TimeUnit timeUnit) {
        return redisTemplate.expire(key,timeOut,timeUnit);
    }
}
---
spring:
  data:
    redis:
      lettuce:
        pool:
          max-idle: 8
          min-idle: 0
          max-wait: -1ms
          max-active: 8
        cluster:
          refresh:
            adaptive: true
            period: 2000
      cluster:
        max-redirects: 3
        nodes: 192.168.189.128:6381,192.168.189.128:6382,192.168.189.130:6383,192.168.189.130:6384,192.168.189.129:6385,192.168.189.129:6386
      password: abc123
      timeout: 5000
---
server:
  port: 8089
  servlet:
    context-path: /
    session:
      persistent: false
---
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/dlyk?useUnicode=true&characterEncoding=utf-8&useSSL=false
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: abc123
    hikari:
      maximum-pool-size: 30
      minimum-idle: 30
      connection-timeout: 5000
      idle-timeout: 0
      max-lifetime: 18000000
---
mybatis:
  mapper-locations: classpath:mapper/*.xml
---
spring:
  data:
    redis:
      lettuce:
        pool:
          max-idle: 8
          min-idle: 0
          max-wait: -1ms
          max-active: 8
        cluster:
          refresh:
            adaptive: true
            period: 2000
      cluster:
        max-redirects: 3
        nodes: 192.168.189.128:6381,192.168.189.128:6382,192.168.189.130:6383,192.168.189.130:6384,192.168.189.129:6385,192.168.189.129:6386
      password: abc123
      timeout: 5000
---
server:
  port: 8089
  servlet:
    context-path: /
    session:
      persistent: false
---
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/dlyk?useUnicode=true&characterEncoding=utf-8&useSSL=false
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: abc123
    hikari:
      maximum-pool-size: 30
      minimum-idle: 30
      connection-timeout: 5000
      idle-timeout: 0
      max-lifetime: 18000000
---
mybatis:
  mapper-locations: classpath:mapper/*.xml

你可能感兴趣的:(CRM项目,#,Spring-Boot框架,#,java,spring,spring,boot,java-ee,redis,后端,json)