当前位置:首页 > 文章列表 > 数据库 > MySQL > 微服务网关Zuul+Spring security+Oauth2.0+Jwt + 动态盐值 实现权限控制,开放接口平台

微服务网关Zuul+Spring security+Oauth2.0+Jwt + 动态盐值 实现权限控制,开放接口平台

来源:SegmentFault 2023-01-23 15:12:54 0浏览 收藏

大家好,今天本人给大家带来文章《微服务网关Zuul+Spring security+Oauth2.0+Jwt + 动态盐值 实现权限控制,开放接口平台》,文中内容主要涉及到MySQL、Redis、Java、安全、springboot,如果你对数据库方面的知识点感兴趣,那就请各位朋友继续看下去吧~希望能真正帮到你们,谢谢!

构建项目

image.png
eureka : 注册中心
common : 公用模块,放置其他服务公用的部分,可以不用
api-gateway : zuul集成security实现登录认证
auth-center : zuul集成security实现认证授权

pom.xml

4.0.0com.babaznkj.comzuul-authpom1.0-SNAPSHOTeurekaapi-gatewaycommonauth-center88UTF-8UTF-81.8Greenwich.SR21.3.21.1.92.0.21.0.0-SNAPSHOTorg.springframework.bootspring-boot-starter-parent2.1.6.RELEASEorg.springframework.cloudspring-cloud-dependencies${spring-cloud.version}pomimportcom.babaznkj.comcommon${project.version}org.springframework.bootspring-boot-maven-plugin
  • common 模块

image.png
  1. JwtProperties.java
    ,这个版本验证 Authorization的时候截取了前6位,且已
    Bearer 
    开头,故在生成jwt的时候要拼接前缀,这个文件就用来读取默认配置的。

    package com.baba.security.common.config;
    
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    
    /**
     * @Author wulongbo
     * @Date 2021/11/4 9:49
     * @Version 1.0
     */
    
    @Data
    @Component
    @ConfigurationProperties("baba.security.jwt")
    public class JwtProperties {
    
     private String secret;
     private String url;
     private String header;
     private String prefix;
     private Integer expiration;
     private String language;
    }
    
  2. JwtTokenAuthenticationFilter.java
    ,由于过滤器中无法注入bean,故采用从spring上下文中获取。做全局异常处理,要抛出自定义异常可以先抛如controller中,当然这里采用了另外一种方式。这里实现了动态验签以及唯一登录。

    package com.baba.security.common.config;
    
    import com.baba.security.common.constant.RedisConstant;
    import com.baba.security.common.enums.ResultCode;
    import com.baba.security.common.exception.DefinitException;
    import com.baba.security.common.utils.JwtUtils;
    import com.baba.security.common.utils.RedisUtils;
    import com.baba.security.common.utils.SpringUtils;
    import io.jsonwebtoken.JwtException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.util.StringUtils;
    import org.springframework.web.context.support.WebApplicationContextUtils;
    import org.springframework.web.filter.OncePerRequestFilter;
    import org.springframework.web.servlet.HandlerExceptionResolver;
    
    import javax.servlet.FilterChain;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.List;
    
    /**
     * Authenticate requests with header 'Authorization: Bearer jwt-token'.
     *
     * @author wulongbo 2021/10/18
     */
    public class JwtTokenAuthenticationFilter extends OncePerRequestFilter {
    
    //    private final JwtAuthenticationConfig config;
     private final JwtProperties config;
    
     public JwtTokenAuthenticationFilter(JwtProperties config) {
         this.config = config;
     }
    
     @Override
     protected void doFilterInternal(HttpServletRequest req, HttpServletResponse rsp, FilterChain filterChain)
             throws ServletException, IOException {
         HandlerExceptionResolver resolver = null;
         try {
             RedisUtils redisUtil = SpringUtils.getBean(RedisUtils.class);
             // filter过滤器使用Autowired注入Bean为null
             ServletContext context = req.getServletContext();
             ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(context);
             resolver = ctx.getBean("handlerExceptionResolver", HandlerExceptionResolver.class);
             String userAgent = req.getHeader("user-agent").toLowerCase();
             String salt = null;
             //获取token
             String token = req.getHeader(config.getHeader());
             if (token != null && token.startsWith(config.getPrefix() + " ")) {
                 token = token.replace(config.getPrefix() + " ", "");
                 String id = redisUtil.get(token);
                 if (StringUtils.isEmpty(id)) {
                     resolver.resolveException(req, rsp, null, new DefinitException(ResultCode.REDIS_CACHE_BLANK));
                     return;
                 }
                 if (userAgent.indexOf("micromessenger") != -1) {
                     //微信
                 } else if (userAgent.indexOf("android") != -1
                         || userAgent.indexOf("iphone") != -1 || userAgent.indexOf("ipad") != -1 || userAgent.indexOf("ipod") != -1) {
                     //安卓 或者 苹果
                     salt = redisUtil.get(RedisConstant.PREFIX_APP + id);
                 } else {
                     //电脑
                     salt = redisUtil.get(RedisConstant.PREFIX_WEB + id);
                 }
                 if (StringUtils.isEmpty(salt)) {
                     resolver.resolveException(req, rsp, null, new DefinitException(ResultCode.REDIS_SALT_BLANK));
                     return;
                 }
                 String username = JwtUtils.getUsername(token,salt);
                 if (username != null) {
                     List roles = JwtUtils.getUserRole(token,salt);
                     SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(username, null, roles));
                 }
             }
    //            resolver.resolveException(req, rsp, null, new JwtException(ResultCode.TOKEN_EXCEPTION.getMessage()));
    
             filterChain.doFilter(req, rsp);
         } catch (JwtException e) {
             resolver.resolveException(req, rsp, null, new JwtException(ResultCode.SAFETY_INVALID.getMessage()));
         }
     }
    }
    
  3. RedisConstant.java
    ,常量类。

    package com.baba.security.common.constant;
    
    /**
     * @author wulongbo 2021/10/18
     */
    public interface RedisConstant {
    
     String TOKEN_TEMPLATE = "token_%s";
    
     String PREFIX_APP = "bbznkj_app_";
    
     String PREFIX_WEB = "bbznkj_web_";
    }
    
  4. ResultCode.java
    ,枚举类可以规范响应,如是多国语言的系统可以考虑适用redis来解决。

    package com.baba.security.common.enums;
    
    /**
     * @Author wulongbo
     * @Date 2021/10/27 14:13
     * @Version 1.0
     */
    
    /**
     * 异常处理状态码
     */
    public enum ResultCode {
    
     SUCCESS(0, "请求成功"),
     FAILED(1001, "响应失败"),
     Unknown_Exception(-1, "未知异常"),
     SAFETY_INVALID(208,"该账号已在其他设备登录,签名已失效,请重新登录"),
     REDIS_CACHE_BLANK(6379, "缓存已失效,请重新登录"),
     REQUEST_URL_WRONG(401, "请求地址不存在"),
     REQUEST_BLANK(403, "请求接口无权限访问"),
     REDIS_SALT_BLANK(6333,"签名值缓存失效"),
     USER_NOT_FOUND(10001, "没有找到此用户"),
     USERNAME_NOT_BLANK(10002, "用户名不能为空"),
     USERNAME_EXIST(10003, "用户名已经存在"),
     USERTYPE_ERROR(100031, "用户类型不正确"),
     PHONE_WROND(10004, "手机号不正确"),
     SMS_CODE_ERROR(10007, "手机验证码不正确"),
     PHONE_EXIST(10008, "手机号已经存在"),
     USER_EMPTY_EXCEPTION(10009, "用户名、手机号或者邮箱为空"),
     USER_TOKEN_EXCEPTION(10010, "从TOKEN中未查到相关用户信息"),
     USERNAME_PASSWORD_EXCEPTION(10011, "用户名或者密码错误"),
    
     EMAIL_SERVER_ECCEPTION(10012, "阿里云邮件服务端出错"),
     EMAIL_CLIENT_ECCEPTION(10013, "阿里云邮件客户端出错"),
     EMAIL_SEND_ECCEPTION(10014, "阿里云邮件发送出错"),
     EMAIL_WROND(10015, "邮箱不正确"),
     EMAIL_CODE_WROND(10016, "邮箱验证码不正确"),
     EMAIL_EXIST(10017, "邮箱已经存在"),
    
     LOGIN_METHOD_WROND(209, "登录密码不正确"),
     CODE_EMPTY(10019, "验证码不为空"),
     PASSWORD_EMPTY(10020, "密码不为空"),
     TOKEN_EXCEPTION(10021, "TOKEN认证出错"),
    
     USER_AUTH_FAILD(10022, "用户认证失败"),
    
     USER_AUTH_SUCCESS(200, "用户认证授权成功"),
    
     USER_ACCESS_DENIED(10023, "用户无权限登录"),
    
     CODE_SEND_FAILD(10030, "验证码发送失败"),
    
     ACTION_MONGODB_ERROR(10100, "操作MONGODB数据库出错"),
     OPERATION_TOO_FREQUENT(10101, "请求过于频繁,请稍候再试"),
    
     CODE_EXIST(10023,"编号已存在"),
     TESTCODE_ERROR(10036,"提交数已达上限"),
     NAME_EXIST(10024,"名称已存在"),
     NOT_EXIST_EMAIL(10025,"该企业用户没有分配邮箱"),
     MAIL_REACH_MAX(10026,"达到收取邮箱上限"),
     MAIL_NEW_NOTEXIST(10027,"邮箱中没有可导入的简历"),
     PWD_CONFIRM_ERROR(10029,"两次密码不一致"),
     PWD_ERROR(10030,"密码不正确"),
     ENTER_OR_TALENT_NOT_EXITS(10028,"企业或人才库简历不存在"),
     PHONE_EMPTY(10031, "手机号不能为空"),
     EMAIL_EMPTY(10032, "邮箱不能为空"),
     NO_USABLE_MAIL(10040,"没有可用邮箱"),
    
     DEVICE_ID_EMPTY(10052,"设备ID:deviceId不能为空"),
     DELETE_CONNECT_ERROR(10053,"删除connect出错");
    
     private int code;
     private String message;
    
     ResultCode(int code, String message) {
         this.code = code;
         this.message = message;
     }
    
     public int getCode() {
         return code;
     }
    
     public String getMessage() {
         return message;
     }
    }
    
  5. ApiException.java
    DefinitException.java
    JWTAuthenticationEntryPoint.java
    ExceptionControllerAdvice.java
    SimpleAccessDeniedHandler.java
    SimpleAuthenticationEntryPoint.java
    、 :自定义异常类,用于全局异常处理。

    package com.baba.security.common.exception;
    import lombok.Getter;
    
    /**
     * @Author wulongbo
     * @Date 2021/10/27 11:58
     * @Version 1.0
     * 自定义异常
     */
    @Getter
    //只要getter方法,无需setter
    public class ApiException extends RuntimeException {
    
     private int code;
     private String msg;
    
     public ApiException() {
         this(1001, "接口错误");
     }
    
     public ApiException(String msg) {
         this(1001, msg);
     }
    
     public ApiException(int code, String msg) {
         super(msg);
         this.code = code;
         this.msg = msg;
     }
    }
    

package com.baba.security.common.exception;

import com.baba.security.common.enums.ResultCode;
import lombok.Data;

/**
 * @Author wulongbo
 * @Date 2021/10/28 11:28
 * @Version 1.0
 */

@Data
public class DefinitException extends RuntimeException {

    private ResultCode resultCode;
    private int code;
    private String msg;

    public DefinitException() {
        this(1001, "接口错误");
    }

    public DefinitException(ResultCode resultCode) {
        this(resultCode.getCode(), resultCode.getMessage());
        this.resultCode=resultCode;
    }

    public DefinitException(int code, String msg) {
        super(msg);
        this.code = code;
        this.msg = msg;
    }
}

package com.baba.security.common.exception;

import com.baba.security.common.enums.ResultCode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;

/**
 * @Author wulongbo
 * @Date 2021/11/2 17:08
 * @Version 1.0
 */
public class JWTAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request,
                         HttpServletResponse response,
                         AuthenticationException authException) throws IOException, ServletException {

        HashMap map = new HashMap(3);
        map.put("uri", request.getRequestURI());
        map.put("code", ResultCode.REQUEST_URL_WRONG.getCode());
        map.put("msg", ResultCode.REQUEST_URL_WRONG.getMessage());
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        response.setCharacterEncoding("utf-8");
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.getWriter().write(new ObjectMapper().writeValueAsString(map));
    }
}

package com.baba.security.common.handler;
import com.baba.security.common.enums.ResultCode;
import com.baba.security.common.exception.ApiException;
import com.baba.security.common.exception.DefinitException;
import com.baba.security.common.vo.ResultVO;
import io.jsonwebtoken.JwtException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * @Author wulongbo
 * @Date 2021/10/27 12:00
 * @Version 1.0
 * 全局异常控制类
 */
@RestControllerAdvice
public class ExceptionControllerAdvice {

    @ExceptionHandler(DefinitException.class)
    public ResultVO handleDefinitException(DefinitException e) {
        // 注意哦,这里返回类型是自定义响应体
        return new ResultVO(e.getResultCode());
    }

    @ExceptionHandler(ApiException.class)
    public ResultVO handleApiException(ApiException e) {
        // 注意哦,这里返回类型是自定义响应体
        return new ResultVO(ResultCode.FAILED, e.getMsg());
    }


    @ExceptionHandler(JwtException.class)
    public  ResultVO handleJwtException(JwtException e) {
        return new ResultVO(ResultCode.SAFETY_INVALID);
    }
}

package com.baba.security.common.handler;

import com.baba.security.common.enums.ResultCode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;

/**
 * @Author wulongbo
 * @Date 2021/10/28 13:49
 * @Version 1.0
 */
public class SimpleAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        //todo your business
        HashMap map = new HashMap(3);
        map.put("uri", request.getRequestURI());
        map.put("code", ResultCode.REQUEST_BLANK.getCode());
        map.put("msg", ResultCode.REQUEST_BLANK.getMessage());
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        response.setCharacterEncoding("utf-8");
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        ObjectMapper objectMapper = new ObjectMapper();
        String resBody = objectMapper.writeValueAsString(map);
        PrintWriter printWriter = response.getWriter();
        printWriter.print(resBody);
        printWriter.flush();
        printWriter.close();
//        throw new DefinitException(ResultCode.REQUEST_BLANK);
    }
}

package com.baba.security.common.handler;

import com.baba.security.common.enums.ResultCode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;

/**
 * @Author wulongbo
 * @Date 2021/10/28 13:49
 * @Version 1.0
 */
public class SimpleAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        HashMap map = new HashMap(2);
        map.put("uri", request.getRequestURI());
        map.put("code", ResultCode.USER_AUTH_FAILD.getCode());
        map.put("msg", ResultCode.USER_AUTH_FAILD.getMessage());
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setCharacterEncoding("utf-8");
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        ObjectMapper objectMapper = new ObjectMapper();
        String resBody = objectMapper.writeValueAsString(map);
        PrintWriter printWriter = response.getWriter();
        printWriter.print(resBody);
        printWriter.flush();
        printWriter.close();
    }
}
  1. 这里就是工具类啦,直接贴不再说明。

    package com.baba.security.common.utils;
    
    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    
    import java.time.Instant;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;
    
    public class JwtUtils {
    
     public static final String TOKEN_HEADER = "token";
     public static final String TOKEN_PREFIX = "Bearer ";
    
     private static final String SUBJECT = "mayikt";
    
     private static final long EXPIRITION = 1000 * 24 * 60 * 60 * 7;
    
     private static final String APPSECRET_KEY = "secret";
    
     private static final String ROLE_CLAIMS = "roles";
    
     private static final String LANGUAGE = "language";
    
     public static String generateJsonWebToken(Authentication auth,String secretKey,String language) {
         Instant now = Instant.now();
         String token = Jwts.builder()
                 .setSubject(auth.getName())
                 .claim(LANGUAGE,language)
                 .claim(ROLE_CLAIMS, auth.getAuthorities().stream()
                         .map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
                 .setIssuedAt(Date.from(now))
                 .setExpiration(Date.from(now.plusSeconds(EXPIRITION)))
                 .signWith(SignatureAlgorithm.HS256, secretKey.getBytes())
                 .compact();
         return token;
     }
    
     /**
      * 生成token
      *
      * @param username
      * @param role
      * @return
      */
     public static String createToken(String username, String role) {
    
         Map map = new HashMap();
         map.put(ROLE_CLAIMS, role);
    
         String token = Jwts
                 .builder()
                 .setSubject(username)
                 .setClaims(map)
                 .claim("username", username)
                 .setIssuedAt(new Date())
                 .setExpiration(new Date(System.currentTimeMillis() + EXPIRITION))
                 .signWith(SignatureAlgorithm.HS256, APPSECRET_KEY).compact();
         return token;
     }
    
     public static Claims checkJWT(String token) {
         try {
             final Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
             return claims;
         } catch (Exception e) {
             e.printStackTrace();
             return null;
         }
     }
    
     /**
      * 获取用户名
      *
      * @param token
      * @return
      */
     public static String getUsername(String token, String secretKey) {
         Claims claims = Jwts.parser()
                 .setSigningKey(secretKey.getBytes())
                 .parseClaimsJws(token)
                 .getBody();
         String username = claims.getSubject();
         return username;
     }
    
     /**
      * 获取用户角色
      *
      * @param token
      * @return
      */
     public static List getUserRole(String token, String secretKey) {
         Claims claims = Jwts.parser()
                 .setSigningKey(secretKey.getBytes())
                 .parseClaimsJws(token)
                 .getBody();
         List authorities = claims.get(ROLE_CLAIMS, List.class);
         return authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
     }
    
     /**
      * 获取用户角色
      *
      * @param token
      * @return
      */
     public static List getUserRole2(String token) {
         Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY.getBytes()).parseClaimsJws(token).getBody();
         List authorities = claims.get("authorities", List.class);
         List roles = authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
         return roles;
     }
    
     /**
      * 是否过期
      *
      * @param token
      * @return
      */
     public static boolean isExpiration(String token) {
         Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
         return claims.getExpiration().before(new Date());
     }
    
    }
    

package com.baba.security.common.utils;

import java.security.MessageDigest;

public class MD5Util {

    private static final String SALT = "mayikt";

    public static String encode(String password) {
        password = password + SALT;
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        char[] charArray = password.toCharArray();
        byte[] byteArray = new byte[charArray.length];

        for (int i = 0; i 

package com.baba.security.common.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Component
public class RedisUtils {

    @Autowired
    private StringRedisTemplate redisTemplate;

    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public StringRedisTemplate getRedisTemplate() {
        return this.redisTemplate;
    }

    /** -------------------key相关操作--------------------- */

    /**
     * 删除key
     *
     * @param key
     */
    public void delete(String key) {
        redisTemplate.delete(key);
    }

    /**
     * 批量删除key
     *
     * @param keys
     */
    public void delete(Collection keys) {
        redisTemplate.delete(keys);
    }

    /**
     * 序列化key
     *
     * @param key
     * @return
     */
    public byte[] dump(String key) {
        return redisTemplate.dump(key);
    }

    /**
     * 是否存在key
     *
     * @param key
     * @return
     */
    public Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 设置过期时间
     *
     * @param key
     * @param timeout
     * @param unit
     * @return
     */
    public Boolean expire(String key, long timeout, TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }

    /**
     * 设置过期时间
     *
     * @param key
     * @param date
     * @return
     */
    public Boolean expireAt(String key, Date date) {
        return redisTemplate.expireAt(key, date);
    }

    /**
     * 查找匹配的key
     *
     * @param pattern
     * @return
     */
    public Set keys(String pattern) {
        return redisTemplate.keys(pattern);
    }

    /**
     * 将当前数据库的 key 移动到给定的数据库 db 当中
     *
     * @param key
     * @param dbIndex
     * @return
     */
    public Boolean move(String key, int dbIndex) {
        return redisTemplate.move(key, dbIndex);
    }

    /**
     * 移除 key 的过期时间,key 将持久保持
     *
     * @param key
     * @return
     */
    public Boolean persist(String key) {
        return redisTemplate.persist(key);
    }

    /**
     * 返回 key 的剩余的过期时间
     *
     * @param key
     * @param unit
     * @return
     */
    public Long getExpire(String key, TimeUnit unit) {
        return redisTemplate.getExpire(key, unit);
    }

    /**
     * 返回 key 的剩余的过期时间
     *
     * @param key
     * @return
     */
    public Long getExpire(String key) {
        return redisTemplate.getExpire(key);
    }

    /**
     * 从当前数据库中随机返回一个 key
     *
     * @return
     */
    public String randomKey() {
        return redisTemplate.randomKey();
    }

    /**
     * 修改 key 的名称
     *
     * @param oldKey
     * @param newKey
     */
    public void rename(String oldKey, String newKey) {
        redisTemplate.rename(oldKey, newKey);
    }

    /**
     * 仅当 newkey 不存在时,将 oldKey 改名为 newkey
     *
     * @param oldKey
     * @param newKey
     * @return
     */
    public Boolean renameIfAbsent(String oldKey, String newKey) {
        return redisTemplate.renameIfAbsent(oldKey, newKey);
    }

    /**
     * 返回 key 所储存的值的类型
     *
     * @param key
     * @return
     */
    public DataType type(String key) {
        return redisTemplate.type(key);
    }

    /** -------------------string相关操作--------------------- */

    /**
     * 设置指定 key 的值
     *
     * @param key
     * @param value
     */
    public void set(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 获取指定 key 的值
     *
     * @param key
     * @return
     */
    public String get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 返回 key 中字符串值的子字符
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public String getRange(String key, long start, long end) {
        return redisTemplate.opsForValue().get(key, start, end);
    }

    /**
     * 将给定 key 的值设为 value ,并返回 key 的旧值(old value)
     *
     * @param key
     * @param value
     * @return
     */
    public String getAndSet(String key, String value) {
        return redisTemplate.opsForValue().getAndSet(key, value);
    }

    /**
     * 对 key 所储存的字符串值,获取指定偏移量上的位(bit)
     *
     * @param key
     * @param offset
     * @return
     */
    public Boolean getBit(String key, long offset) {
        return redisTemplate.opsForValue().getBit(key, offset);
    }

    /**
     * 批量获取
     *
     * @param keys
     * @return
     */
    public List multiGet(Collection keys) {
        return redisTemplate.opsForValue().multiGet(keys);
    }

    /**
     * 设置ASCII码, 字符串'a'的ASCII码是97, 转为二进制是'01100001', 此方法是将二进制第offset位值变为value
     *
     * @param key   位置
     * @param value 值,true为1, false为0
     * @return
     */
    public boolean setBit(String key, long offset, boolean value) {
        return redisTemplate.opsForValue().setBit(key, offset, value);
    }

    /**
     * 将值 value 关联到 key ,并将 key 的过期时间设为 timeout
     *
     * @param key
     * @param value
     * @param timeout 过期时间
     * @param unit    时间单位, 天:TimeUnit.DAYS 小时:TimeUnit.HOURS 分钟:TimeUnit.MINUTES
     *                秒:TimeUnit.SECONDS 毫秒:TimeUnit.MILLISECONDS
     */
    public void setEx(String key, String value, long timeout, TimeUnit unit) {
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }

    /**
     * 只有在 key 不存在时设置 key 的值
     *
     * @param key
     * @param value
     * @return 之前已经存在返回false, 不存在返回true
     */
    public boolean setIfAbsent(String key, String value) {
        return redisTemplate.opsForValue().setIfAbsent(key, value);
    }

    /**
     * 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始
     *
     * @param key
     * @param value
     * @param offset 从指定位置开始覆写
     */
    public void setRange(String key, String value, long offset) {
        redisTemplate.opsForValue().set(key, value, offset);
    }

    /**
     * 获取字符串的长度
     *
     * @param key
     * @return
     */
    public Long size(String key) {
        return redisTemplate.opsForValue().size(key);
    }

    /**
     * 批量添加
     *
     * @param maps
     */
    public void multiSet(Map maps) {
        redisTemplate.opsForValue().multiSet(maps);
    }

    /**
     * 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在
     *
     * @param maps
     * @return 之前已经存在返回false, 不存在返回true
     */
    public boolean multiSetIfAbsent(Map maps) {
        return redisTemplate.opsForValue().multiSetIfAbsent(maps);
    }

    /**
     * 增加(自增长), 负数则为自减
     *
     * @param key
     * @return
     */
    public Long incrBy(String key, long increment) {
        return redisTemplate.opsForValue().increment(key, increment);
    }

    /**
     * @param key
     * @return
     */
    public Double incrByFloat(String key, double increment) {
        return redisTemplate.opsForValue().increment(key, increment);
    }

    /**
     * 追加到末尾
     *
     * @param key
     * @param value
     * @return
     */
    public Integer append(String key, String value) {
        return redisTemplate.opsForValue().append(key, value);
    }

    /** -------------------hash相关操作------------------------- */

    /**
     * 获取存储在哈希表中指定字段的值
     *
     * @param key
     * @param field
     * @return
     */
    public T hGet(String key, String field) {
        return (T)redisTemplate.opsForHash().get(key, field);
    }

    /**
     * 获取所有给定字段的值
     *
     * @param key
     * @return
     */
    public Map hGetAll(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 获取所有给定字段的值
     *
     * @param key
     * @param fields
     * @return
     */
    public List hMultiGet(String key, Collection fields) {
        return (List)redisTemplate.opsForHash().multiGet(key, fields);
    }

    public void hPut(String key, String hashKey, String value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    public void hPut(String key, String hashKey, Integer value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    public void hPutAll(String key, Map maps) {
        redisTemplate.opsForHash().putAll(key, maps);
    }

    /**
     * 仅当hashKey不存在时才设置
     *
     * @param key
     * @param hashKey
     * @param value
     * @return
     */
    public Boolean hPutIfAbsent(String key, String hashKey, String value) {
        return redisTemplate.opsForHash().putIfAbsent(key, hashKey, value);
    }

    /**
     * 删除一个或多个哈希表字段
     *
     * @param key
     * @param fields
     * @return
     */
    public Long hDelete(String key, Object... fields) {
        return redisTemplate.opsForHash().delete(key, fields);
    }

    /**
     * 查看哈希表 key 中,指定的字段是否存在
     *
     * @param key
     * @param field
     * @return
     */
    public boolean hExists(String key, String field) {
        return redisTemplate.opsForHash().hasKey(key, field);
    }

    /**
     * 为哈希表 key 中的指定字段的整数值加上增量 increment
     *
     * @param key
     * @param field
     * @param increment
     * @return
     */
    public Long hIncrBy(String key, Object field, long increment) {
        return redisTemplate.opsForHash().increment(key, field, increment);
    }

    /**
     * 为哈希表 key 中的指定字段的整数值加上增量 increment
     *
     * @param key
     * @param field
     * @param delta
     * @return
     */
    public Double hIncrByFloat(String key, Object field, double delta) {
        return redisTemplate.opsForHash().increment(key, field, delta);
    }

    /**
     * 获取所有哈希表中的字段
     *
     * @param key
     * @return
     */
    public Set hKeys(String key) {
        return (Set) redisTemplate.opsForHash().keys(key);
    }

    /**
     * 获取哈希表中字段的数量
     *
     * @param key
     * @return
     */
    public Long hSize(String key) {
        return redisTemplate.opsForHash().size(key);
    }

    /**
     * 获取哈希表中所有值
     *
     * @param key
     * @return
     */
    public List hValues(String key) {
        return (List) redisTemplate.opsForHash().values(key);
    }

    /**
     * 迭代哈希表中的键值对
     *
     * @param key
     * @param options
     * @return
     */
    public Cursor> hScan(String key, ScanOptions options) {
        return redisTemplate.opsForHash().scan(key, options);
    }

    /** ------------------------list相关操作---------------------------- */

    /**
     * 通过索引获取列表中的元素
     *
     * @param key
     * @param index
     * @return
     */
    public String lIndex(String key, long index) {
        return redisTemplate.opsForList().index(key, index);
    }

    /**
     * 获取列表指定范围内的元素
     *
     * @param key
     * @param start 开始位置, 0是开始位置
     * @param end   结束位置, -1返回所有
     * @return
     */
    public List lRange(String key, long start, long end) {
        return redisTemplate.opsForList().range(key, start, end);
    }

    /**
     * 存储在list头部
     *
     * @param key
     * @param value
     * @return
     */
    public Long lLeftPush(String key, String value) {
        return redisTemplate.opsForList().leftPush(key, value);
    }

    /**
     * @param key
     * @param value
     * @return
     */
    public Long lLeftPushAll(String key, String... value) {
        return redisTemplate.opsForList().leftPushAll(key, value);
    }

    /**
     * @param key
     * @param value
     * @return
     */
    public Long lLeftPushAll(String key, Collection value) {
        return redisTemplate.opsForList().leftPushAll(key, value);
    }

    /**
     * 当list存在的时候才加入
     *
     * @param key
     * @param value
     * @return
     */
    public Long lLeftPushIfPresent(String key, String value) {
        return redisTemplate.opsForList().leftPushIfPresent(key, value);
    }

    /**
     * 如果pivot存在,再pivot前面添加
     *
     * @param key
     * @param pivot
     * @param value
     * @return
     */
    public Long lLeftPush(String key, String pivot, String value) {
        return redisTemplate.opsForList().leftPush(key, pivot, value);
    }

    /**
     * @param key
     * @param value
     * @return
     */
    public Long lRightPush(String key, String value) {
        return redisTemplate.opsForList().rightPush(key, value);
    }

    /**
     * @param key
     * @param value
     * @return
     */
    public Long lRightPushAll(String key, String... value) {
        return redisTemplate.opsForList().rightPushAll(key, value);
    }

    /**
     * @param key
     * @param value
     * @return
     */
    public Long lRightPushAll(String key, Collection value) {
        return redisTemplate.opsForList().rightPushAll(key, value);
    }

    /**
     * 为已存在的列表添加值
     *
     * @param key
     * @param value
     * @return
     */
    public Long lRightPushIfPresent(String key, String value) {
        return redisTemplate.opsForList().rightPushIfPresent(key, value);
    }

    /**
     * 在pivot元素的右边添加值
     *
     * @param key
     * @param pivot
     * @param value
     * @return
     */
    public Long lRightPush(String key, String pivot, String value) {
        return redisTemplate.opsForList().rightPush(key, pivot, value);
    }

    /**
     * 通过索引设置列表元素的值
     *
     * @param key
     * @param index 位置
     * @param value
     */
    public void lSet(String key, long index, String value) {
        redisTemplate.opsForList().set(key, index, value);
    }

    /**
     * 移出并获取列表的第一个元素
     *
     * @param key
     * @return 删除的元素
     */
    public String lLeftPop(String key) {
        return redisTemplate.opsForList().leftPop(key);
    }

    /**
     * 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
     *
     * @param key
     * @param timeout 等待时间
     * @param unit    时间单位
     * @return
     */
    public String lBLeftPop(String key, long timeout, TimeUnit unit) {
        return redisTemplate.opsForList().leftPop(key, timeout, unit);
    }

    /**
     * 移除并获取列表最后一个元素
     *
     * @param key
     * @return 删除的元素
     */
    public String lRightPop(String key) {
        return redisTemplate.opsForList().rightPop(key);
    }

    /**
     * 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
     *
     * @param key
     * @param timeout 等待时间
     * @param unit    时间单位
     * @return
     */
    public String lBRightPop(String key, long timeout, TimeUnit unit) {
        return redisTemplate.opsForList().rightPop(key, timeout, unit);
    }

    /**
     * 移除列表的最后一个元素,并将该元素添加到另一个列表并返回
     *
     * @param sourceKey
     * @param destinationKey
     * @return
     */
    public String lRightPopAndLeftPush(String sourceKey, String destinationKey) {
        return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey,
                destinationKey);
    }

    /**
     * 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
     *
     * @param sourceKey
     * @param destinationKey
     * @param timeout
     * @param unit
     * @return
     */
    public String lBRightPopAndLeftPush(String sourceKey, String destinationKey,
                                        long timeout, TimeUnit unit) {
        return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey,
                destinationKey, timeout, unit);
    }

    /**
     * 删除集合中值等于value得元素
     *
     * @param key
     * @param index index=0, 删除所有值等于value的元素; index>0, 从头部开始删除第一个值等于value的元素;
     *              index sIntersect(String key, String otherKey) {
        return redisTemplate.opsForSet().intersect(key, otherKey);
    }

    /**
     * 获取key集合与多个集合的交集
     *
     * @param key
     * @param otherKeys
     * @return
     */
    public Set sIntersect(String key, Collection otherKeys) {
        return redisTemplate.opsForSet().intersect(key, otherKeys);
    }

    /**
     * key集合与otherKey集合的交集存储到destKey集合中
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
    public Long sIntersectAndStore(String key, String otherKey, String destKey) {
        return redisTemplate.opsForSet().intersectAndStore(key, otherKey,
                destKey);
    }

    /**
     * key集合与多个集合的交集存储到destKey集合中
     *
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
    public Long sIntersectAndStore(String key, Collection otherKeys,
                                   String destKey) {
        return redisTemplate.opsForSet().intersectAndStore(key, otherKeys,
                destKey);
    }

    /**
     * 获取两个集合的并集
     *
     * @param key
     * @param otherKeys
     * @return
     */
    public Set sUnion(String key, String otherKeys) {
        return redisTemplate.opsForSet().union(key, otherKeys);
    }

    /**
     * 获取key集合与多个集合的并集
     *
     * @param key
     * @param otherKeys
     * @return
     */
    public Set sUnion(String key, Collection otherKeys) {
        return redisTemplate.opsForSet().union(key, otherKeys);
    }

    /**
     * key集合与otherKey集合的并集存储到destKey中
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
    public Long sUnionAndStore(String key, String otherKey, String destKey) {
        return redisTemplate.opsForSet().unionAndStore(key, otherKey, destKey);
    }

    /**
     * key集合与多个集合的并集存储到destKey中
     *
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
    public Long sUnionAndStore(String key, Collection otherKeys,
                               String destKey) {
        return redisTemplate.opsForSet().unionAndStore(key, otherKeys, destKey);
    }

    /**
     * 获取两个集合的差集
     *
     * @param key
     * @param otherKey
     * @return
     */
    public Set sDifference(String key, String otherKey) {
        return redisTemplate.opsForSet().difference(key, otherKey);
    }

    /**
     * 获取key集合与多个集合的差集
     *
     * @param key
     * @param otherKeys
     * @return
     */
    public Set sDifference(String key, Collection otherKeys) {
        return redisTemplate.opsForSet().difference(key, otherKeys);
    }

    /**
     * key集合与otherKey集合的差集存储到destKey中
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
    public Long sDifference(String key, String otherKey, String destKey) {
        return redisTemplate.opsForSet().differenceAndStore(key, otherKey,
                destKey);
    }

    /**
     * key集合与多个集合的差集存储到destKey中
     *
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
    public Long sDifference(String key, Collection otherKeys,
                            String destKey) {
        return redisTemplate.opsForSet().differenceAndStore(key, otherKeys,
                destKey);
    }

    /**
     * 获取集合所有元素
     *
     * @param key
     * @return
     */
    public Set setMembers(String key) {
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * 随机获取集合中的一个元素
     *
     * @param key
     * @return
     */
    public String sRandomMember(String key) {
        return redisTemplate.opsForSet().randomMember(key);
    }

    /**
     * 随机获取集合中count个元素
     *
     * @param key
     * @param count
     * @return
     */
    public List sRandomMembers(String key, long count) {
        return redisTemplate.opsForSet().randomMembers(key, count);
    }

    /**
     * 随机获取集合中count个元素并且去除重复的
     *
     * @param key
     * @param count
     * @return
     */
    public Set sDistinctRandomMembers(String key, long count) {
        return redisTemplate.opsForSet().distinctRandomMembers(key, count);
    }

    /**
     * @param key
     * @param options
     * @return
     */
    public Cursor sScan(String key, ScanOptions options) {
        return redisTemplate.opsForSet().scan(key, options);
    }

    /**------------------zSet相关操作--------------------------------*/

    /**
     * 添加元素,有序集合是按照元素的score值由小到大排列
     *
     * @param key
     * @param value
     * @param score
     * @return
     */
    public Boolean zAdd(String key, String value, double score) {
        return redisTemplate.opsForZSet().add(key, value, score);
    }

    /**
     * @param key
     * @param values
     * @return
     */
    public Long zAdd(String key, Set> values) {
        return redisTemplate.opsForZSet().add(key, values);
    }

    /**
     * @param key
     * @param values
     * @return
     */
    public Long zRemove(String key, Object... values) {
        return redisTemplate.opsForZSet().remove(key, values);
    }

    /**
     * 增加元素的score值,并返回增加后的值
     *
     * @param key
     * @param value
     * @param delta
     * @return
     */
    public Double zIncrementScore(String key, String value, double delta) {
        return redisTemplate.opsForZSet().incrementScore(key, value, delta);
    }

    /**
     * 返回元素在集合的排名,有序集合是按照元素的score值由小到大排列
     *
     * @param key
     * @param value
     * @return 0表示第一位
     */
    public Long zRank(String key, Object value) {
        return redisTemplate.opsForZSet().rank(key, value);
    }

    /**
     * 返回元素在集合的排名,按元素的score值由大到小排列
     *
     * @param key
     * @param value
     * @return
     */
    public Long zReverseRank(String key, Object value) {
        return redisTemplate.opsForZSet().reverseRank(key, value);
    }

    /**
     * 获取集合的元素, 从小到大排序
     *
     * @param key
     * @param start 开始位置
     * @param end   结束位置, -1查询所有
     * @return
     */
    public Set zRange(String key, long start, long end) {
        return redisTemplate.opsForZSet().range(key, start, end);
    }

    /**
     * 获取集合元素, 并且把score值也获取
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public Set> zRangeWithScores(String key, long start,
                                                                   long end) {
        return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
    }

    /**
     * 根据Score值查询集合元素
     *
     * @param key
     * @param min 最小值
     * @param max 最大值
     * @return
     */
    public Set zRangeByScore(String key, double min, double max) {
        return redisTemplate.opsForZSet().rangeByScore(key, min, max);
    }

    /**
     * 根据Score值查询集合元素, 从小到大排序
     *
     * @param key
     * @param min 最小值
     * @param max 最大值
     * @return
     */
    public Set> zRangeByScoreWithScores(String key,
                                                                          double min, double max) {
        return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max);
    }

    /**
     * @param key
     * @param min
     * @param max
     * @param start
     * @param end
     * @return
     */
    public Set> zRangeByScoreWithScores(String key,
                                                                          double min, double max, long start, long end) {
        return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max,
                start, end);
    }

    /**
     * 获取集合的元素, 从大到小排序
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public Set zReverseRange(String key, long start, long end) {
        return redisTemplate.opsForZSet().reverseRange(key, start, end);
    }

    /**
     * 获取集合的元素, 从大到小排序, 并返回score值
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public Set> zReverseRangeWithScores(String key,
                                                                          long start, long end) {
        return redisTemplate.opsForZSet().reverseRangeWithScores(key, start,
                end);
    }

    /**
     * 根据Score值查询集合元素, 从大到小排序
     *
     * @param key
     * @param min
     * @param max
     * @return
     */
    public Set zReverseRangeByScore(String key, double min,
                                            double max) {
        return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max);
    }

    /**
     * 根据Score值查询集合元素, 从大到小排序
     *
     * @param key
     * @param min
     * @param max
     * @return
     */
    public Set> zReverseRangeByScoreWithScores(
            String key, double min, double max) {
        return redisTemplate.opsForZSet().reverseRangeByScoreWithScores(key,
                min, max);
    }

    /**
     * @param key
     * @param min
     * @param max
     * @param start
     * @param end
     * @return
     */
    public Set zReverseRangeByScore(String key, double min,
                                            double max, long start, long end) {
        return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max,
                start, end);
    }

    /**
     * 根据score值获取集合元素数量
     *
     * @param key
     * @param min
     * @param max
     * @return
     */
    public Long zCount(String key, double min, double max) {
        return redisTemplate.opsForZSet().count(key, min, max);
    }

    /**
     * 获取集合大小
     *
     * @param key
     * @return
     */
    public Long zSize(String key) {
        return redisTemplate.opsForZSet().size(key);
    }

    /**
     * 获取集合大小
     *
     * @param key
     * @return
     */
    public Long zZCard(String key) {
        return redisTemplate.opsForZSet().zCard(key);
    }

    /**
     * 获取集合中value元素的score值
     *
     * @param key
     * @param value
     * @return
     */
    public Double zScore(String key, Object value) {
        return redisTemplate.opsForZSet().score(key, value);
    }

    /**
     * 移除指定索引位置的成员
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public Long zRemoveRange(String key, long start, long end) {
        return redisTemplate.opsForZSet().removeRange(key, start, end);
    }

    /**
     * 根据指定的score值的范围来移除成员
     *
     * @param key
     * @param min
     * @param max
     * @return
     */
    public Long zRemoveRangeByScore(String key, double min, double max) {
        return redisTemplate.opsForZSet().removeRangeByScore(key, min, max);
    }

    /**
     * 获取key和otherKey的并集并存储在destKey中
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
    public Long zUnionAndStore(String key, String otherKey, String destKey) {
        return redisTemplate.opsForZSet().unionAndStore(key, otherKey, destKey);
    }

    /**
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
    public Long zUnionAndStore(String key, Collection otherKeys,
                               String destKey) {
        return redisTemplate.opsForZSet()
                .unionAndStore(key, otherKeys, destKey);
    }

    /**
     * 交集
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
    public Long zIntersectAndStore(String key, String otherKey,
                                   String destKey) {
        return redisTemplate.opsForZSet().intersectAndStore(key, otherKey,
                destKey);
    }

    /**
     * 交集
     *
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
    public Long zIntersectAndStore(String key, Collection otherKeys,
                                   String destKey) {
        return redisTemplate.opsForZSet().intersectAndStore(key, otherKeys,
                destKey);
    }

    /**
     * @param key
     * @param options
     * @return
     */
    public Cursor> zScan(String key, ScanOptions options) {
        return redisTemplate.opsForZSet().scan(key, options);
    }
}

package com.baba.security.common.utils;

import java.util.Random;

/**
 * @Author wulongbo
 * @Date 2021/10/25 15:54
 * @Version 1.0
 */
public class SaltUtils {

    /**
     * 生成salt的静态方法
     */
    public static String getSalt(int n) {
        char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!@#$%^&*()_+".toCharArray();
        int length = chars.length;
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i 

package com.baba.security.common.utils;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.Locale;

/**
 * @Author wulongbo
 * @Date 2021/11/2 17:21
 * @Version 1.0
 */
@Component
public class SpringUtils implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    // 设置上下文
    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        if (SpringUtils.applicationContext == null) {
            SpringUtils.applicationContext = applicationContext;
        }

    }

    //获取上下文
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    // 通过名字获取上下文的Bean
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    //通过类型获取上下文的bean
    public static  T getBean(Class clazz) {
        return getApplicationContext().getBean(clazz);
    }

    public static  T getBean(String name, Class clazz) {
        return getApplicationContext().getBean(name, clazz);
    }

    // 国际化使用
    public static String getMessage(String key) {
        return applicationContext.getMessage(key, null, Locale.getDefault());
    }

    // 获取当前环境
    public static String[] getActiveProfiles() {
        return applicationContext.getEnvironment().getActiveProfiles();
    }

    // 判断当前环境是否为test/local
    public static boolean isDevEnv() {
        String[] activeProfiles = getActiveProfiles();
        if (activeProfiles.length 
  1. VO响应对象

    package com.baba.security.common.vo;
    import com.baba.security.common.enums.ResultCode;
    import lombok.Data;
    
    /**
     * @Author wulongbo
     * @Date 2021/10/27 14:18
     * @Version 1.0
     */
    
    @Data
    public class ResultVO {
     /**
      * 状态码,比如1000代表响应成功
      */
     private int code;
     /**
      * 响应信息,用来说明响应情况
      */
     private String msg;
     /**
      * 响应的具体数据
      */
     private T data;
    
     public ResultVO(T data) {
         this(ResultCode.SUCCESS,data);
     }
    
     public ResultVO(ResultCode resultCode, T data) {
         this.code = resultCode.getCode();
         this.msg = resultCode.getMessage();
         this.data = data;
     }
    
     public ResultVO(ResultCode resultCode) {
         this.code = resultCode.getCode();
         this.msg = resultCode.getMessage();
     }
    }
    

    自此 common模块就写完成,后面我们来完成登录认证模块

到这里,我们也就讲完了《微服务网关Zuul+Spring security+Oauth2.0+Jwt + 动态盐值 实现权限控制,开放接口平台》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于mysql的知识点!

版本声明
本文转载于:SegmentFault 如有侵犯,请联系study_golang@163.com删除
微服务网关Zuul+Spring security+Oauth2.0+Jwt + 动态盐值 实现权限控制,开放接口平台(3)微服务网关Zuul+Spring security+Oauth2.0+Jwt + 动态盐值 实现权限控制,开放接口平台(3)
上一篇
微服务网关Zuul+Spring security+Oauth2.0+Jwt + 动态盐值 实现权限控制,开放接口平台(3)
尚硅谷《宋红康MySQL核心+高级》全套教程即将发布
下一篇
尚硅谷《宋红康MySQL核心+高级》全套教程即将发布
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • ChatExcel酷表:告别Excel难题,北大团队AI助手助您轻松处理数据
    ChatExcel酷表
    ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
    6132次使用
  • Any绘本:开源免费AI绘本创作工具深度解析
    Any绘本
    探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
    6542次使用
  • 可赞AI:AI驱动办公可视化智能工具,一键高效生成文档图表脑图
    可赞AI
    可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
    6355次使用
  • 星月写作:AI网文创作神器,助力爆款小说速成
    星月写作
    星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
    8319次使用
  • MagicLight.ai:叙事驱动AI动画视频创作平台 | 高效生成专业级故事动画
    MagicLight
    MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
    6950次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码