springboot+shiro+jwt+redis完成用户登录认证以及角色授权

1.项目结构

项目结构

2.pom.xl

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--引入shiro整合Springboot依赖-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.5.3</version>
        </dependency>
        <!--引入jwt-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <!--redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--myql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--mybatis plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.0</version>
        </dependency>
        <!--逆向工程-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.1</version>
        </dependency>
        <!--freemarker-->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
        </dependency>
        <!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.6</version>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.5.7</version>
        </dependency>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.15</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>

3.application.yml

server:
  port: 8082
spring:
  # 数据源
  datasource:
    url: jdbc:mysql://localhost:3306/test01?allowPublicKeyRetrieval=true&useSSL=false
    username: root
    password: root123456
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
  # Redis
  redis:
    host: 127.0.0.1
    port: 6379
    database: 0
# MybatisPlus
mybatis-plus:
  global-config:
    db-config:
      field-strategy: IGNORED
      column-underline: true
      logic-delete-field: isDeleted # 全局逻辑删除的实体字段名
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
      db-type: mysql
      id-type: assign_id
  mapper-locations: classpath*:/mapper/**Mapper.xml
  type-aliases-package: com.wuyuan.test01.entiry
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#jwt
jwt:
  secret: zhifou_secret!

# MD5加盐
app:
  security:
    salt: "randomSaltValue"

4.controller

package com.example.test01.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.test01.common.Result;
import com.example.test01.entity.User;
import com.example.test01.service.LoginService;
import com.example.test01.utils.JwtUtil;
import com.example.test01.utils.PasswordUtil;
import com.example.test01.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {

    @Autowired
    private PasswordUtil passwordUtil;

    @Autowired
    private LoginService loginService;

    @Autowired
    private RedisUtil redisUtil;
    @PostMapping("/login")
    public Result<String> login(@RequestBody User user){
        String name = user.getName();
        String password = passwordUtil.encryptPassword(user.getPassword(),1024);
        LambdaQueryWrapper<User> lambdaQueryWrapper =  new LambdaQueryWrapper();
        lambdaQueryWrapper.eq(User::getName,name);
        User findUser = loginService.getOne(lambdaQueryWrapper);
        if(findUser == null){
            return Result.error("用户名错误");
        }else if(!password.equals(findUser.getPassword())){
            return Result.error("密码错误");
        }
        log.info("从数据库中获取用户"+findUser);
//        生成token
        String token = JwtUtil.generateToken(name);
//        把用户信息存到redis
        redisUtil.setObject(token,findUser,60*60*24);
        return Result.success(token);

    }



    @PostMapping("/register")
    public Result<String> register(@RequestBody User user){
//        设置散列次数
        int hashIterations = 1024;
        String name = user.getName();
//        生成默认密码
        if (name.length() < 10) {
            return Result.error(0,"用户名至少需要十位");
        }
        String password = name.substring(name.length() - 6) + "@sky!";
        System.out.print("密码"+password);
        String newPassword = passwordUtil.encryptPassword(password, hashIterations);
        user.setPassword(newPassword);
        boolean save = loginService.save(user);
        if(save){
           return Result.success("用户添加成功");
        }else {
            return Result.error("用户添加失败");
        }

    }

//    获取所有用户
    @GetMapping("/all")
    public Result<List<User>> getAllUser(){
        List<User> list = loginService.list();
        return Result.success(list);
    }


//    修改用户角色(只有管理员有这个权限)
    @RequiresRoles({"2"})
    @PostMapping("/edit")
    public Result<String> eidtUser(@RequestBody User user){
        LambdaQueryWrapper<User> lambdaQueryWrapper =  new LambdaQueryWrapper();
        lambdaQueryWrapper.eq(User::getId,user.getId());
        loginService.update(user,lambdaQueryWrapper);
        return Result.success("修改成功");
    }
}

service类

package com.example.test01.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.test01.common.Result;
import com.example.test01.entity.User;
import org.springframework.stereotype.Component;

import java.util.List;


public interface LoginService extends IService<User> {


}

impl类

package com.example.test01.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.test01.entity.User;
import com.example.test01.mapper.UserMapper;
import com.example.test01.service.LoginService;
import org.springframework.stereotype.Service;


@Service
public class LoginServiceImpl extends ServiceImpl<UserMapper, User> implements LoginService {
}

mapper

package com.example.test01.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.test01.entity.User;
import org.apache.ibatis.annotations.Mapper;


@Mapper
public interface UserMapper extends BaseMapper<User> {
}

entity

package com.example.test01.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;


@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("t_user")
public class User implements Serializable {
    private Long id;
    private String name;
    private String password;
    private Long role;
}

common模块

  • 自定义异常类CustomException
package com.example.test01.common;


public class CustomException extends RuntimeException{
   private final int errCode;
    public  CustomException(int code,String msg){
        super(msg);
        this.errCode = code;
    }


    public int getErrCode(){
        return errCode;
    }
}

  • 自定义全局异常捕获类GlobalExceptionHandler
package com.example.test01.common;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.util.HashMap;
import java.util.Map;


@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(CustomException.class)
     public ResponseEntity<Result<String>> handleCustomException(CustomException ex){
         int code = ex.getErrCode();
        return new ResponseEntity<>(Result.error(code,ex.getMessage()), HttpStatus.OK);
     }


     @ExceptionHandler(Exception.class)
     public ResponseEntity<Result<String>> handleOtherExceptions(Exception ex){
         return new ResponseEntity<>(Result.error(0,ex.getMessage()), HttpStatus.OK);
     }


    @ExceptionHandler(AuthenticationException.class)
    public ResponseEntity<Result<String>> handleAuthenticationException(AuthenticationException ex) {
        return new ResponseEntity<>(Result.error(401,ex.getMessage()), HttpStatus.OK); // 返回 401 Unauthorized
    }

    @ExceptionHandler(UnauthorizedException.class)
    public ResponseEntity<Result<String>> handleUnauthorizedException(UnauthorizedException ex) {
        // 自定义中文提示
        String message = "您没有访问该资源的权限";
        if (ex.getMessage().contains("role")) {
            message = "您没有该角色的权限";
        } else if (ex.getMessage().contains("permission")) {
            message = "您没有该操作的权限";
        }
        // 返回统一格式的响应
        Result<String> result = Result.error(403, message);
        return new ResponseEntity<>(result, HttpStatus.OK); // 403 Forbidden
    }

}

  • 封装的返回类Result
package com.example.test01.common;

import com.baomidou.mybatisplus.extension.api.R;
import lombok.Data;


@Data
public class Result<T> {
    private Integer code;
    private String msg;
    private T data;

    public static <T> Result<T> success(T obj){
        Result<T> r = new Result<T>();
        r.data = obj;
        r.code = 1;
        return r;
    };

    public static <T> Result<T> success(T obj,String msg){
        Result<T> r = new Result<T>();
        r.data = obj;
        r.code = 1;
        r.msg = msg;
        return r;
    };

    public static <T> Result<T> error(String msg){
        Result<T> r = new Result<T>();
        r.data = null;
        r.code = 0;
        r.msg = msg;
        return r;
    }
    public static <T> Result<T> error(Integer code,String msg){
        Result<T> r = new Result<T>();
        r.data = null;
        r.code = code;
        r.msg = msg;
        return r;
    }
    public static <T> Result<T> noLogin(String msg){
        Result<T> r = new Result<T>();
        r.data = null;
        r.code = 1102;
        r.msg = msg;
        return r;
    }



}

  • JwtToken类
package com.example.test01.common;

import org.apache.shiro.authc.AuthenticationToken;

public class JwtToken implements AuthenticationToken {

    private String token;

    public JwtToken(String token) {
        this.token = token;
    }

    @Override
    public Object getPrincipal() {
        return token;
    }

    @Override
    public Object getCredentials() {
        return token;
    }
}

  • 自定义的JwtFilter过滤类
package com.example.test01.common;

import com.example.test01.utils.Utils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class JwtFilter extends AuthenticatingFilter {

    /**
     * 获取token
     *
     * @param servletRequest
     * @param servletResponse
     * @return
     * @throws Exception
     */
    @Override
    protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        String requestToken = getRequestToken((HttpServletRequest) servletRequest);
        JwtToken jwtToken = new JwtToken(requestToken);
        return jwtToken;
    }

    /**
     * 对跨域提供支持
     *
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
//    在请求被处理之前执行的操作。可以在这里进行一些预处理逻辑。
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
        httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
        // 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态
        if (httpServletRequest.getMethod().equalsIgnoreCase("OPTIONS")) {
            httpServletResponse.setStatus(200);
            return false;
        }
        return super.preHandle(request, response);
    }

    /**
     * 验证token
     * 当访问拒绝时是否已经处理了;
     * 如果返回true表示需要继续处理;
     * 如果返回false表示该拦截器实例已经处理完成了,将直接返回即可。
     *
     * @param servletRequest
     * @param servletResponse
     * @return
     * @throws Exception
     */
//    当访问被拒绝时(即未登录或身份验证失败),此方法会被调用
    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        //完成token登入
        //1.检查请求头中是否含有token
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        String token = getRequestToken(httpServletRequest);
        //2. 如果客户端没有携带token,拦下请求
        if (null == token || "".equals(token)) {
            Utils.responseToken(servletResponse, "Token无效(authorization不存在)", HttpStatus.UNAUTHORIZED.value());
            return false;
        }
        //3. 如果有,对进行进行token验证
        return this.executeLogin(servletRequest, servletResponse);
    }

    /**
     * 执行认证
     *
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    public boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        JwtToken jwtToken = (JwtToken) createToken(request, response);
        try {
            SecurityUtils.getSubject().login(jwtToken);
        } catch (Exception e) {
            if (e.getClass().getName().equalsIgnoreCase(AuthenticationException.class.getName())) {
                Utils.responseToken(response, "Token无效,您无权访问该接口!", HttpStatus.UNAUTHORIZED.value());
            } else if (e.getClass().getName().equalsIgnoreCase(UnknownAccountException.class.getName())) {
                Utils.responseToken(response, "用户名不存在!", HttpStatus.SERVICE_UNAVAILABLE.value());
            } else if (e.getClass().getName().equalsIgnoreCase(IncorrectCredentialsException.class.getName())) {
                Utils.responseToken(response, "密码错误!", HttpStatus.SERVICE_UNAVAILABLE.value());
            } else if (e.getClass().getName().equalsIgnoreCase(ExpiredCredentialsException.class.getName())) {
                Utils.responseToken(response, "Token已过期!", HttpStatus.SERVICE_UNAVAILABLE.value());
            } else {
                Utils.responseToken(response, "其他错误!", HttpStatus.SERVICE_UNAVAILABLE.value());
            }
            return false;
        }
        return true;
    }

//    当用户登录成功时,此方法会被调用
    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
        // 可以记录日志或返回自定义的成功响应

        return false; // 不继续执行后续过滤器链
    }
    /**
     * 获取请求的token
     */
    private String getRequestToken(HttpServletRequest httpRequest) {
        //从header中获取token
        String token = httpRequest.getHeader("authorization");

        //如果header中不存在token,则从参数中获取token
        if (StringUtils.isEmpty(token)) {
            token = httpRequest.getParameter("authorization");
        }
        return token;
    }
}

一些配置类

  • shiro的配置类
package com.example.test01.config;

import com.example.test01.common.JwtFilter;
import com.example.test01.realm.UserRealm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

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

/**
 * ClassName:ShiroConfig
 * Description:
 *
 * @Author 屈亮
 * @Create 2025/3/26 14:33
 * @Version 1.0
 */
@Configuration
public class ShiroConfig {


//   1. 注入自定义身份认证
    @Bean("useRealm")
    public UserRealm userRealm(){
        return new UserRealm();
    }

//    2.将自定义的realm注入到安全管理器中

    @Bean("securityManager")
    public DefaultWebSecurityManager securityManager(@Qualifier("useRealm")UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);

        // 禁用 Session
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator sessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        sessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(sessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);

        return securityManager;

    }


//    3.创建ShiroFilterFactoryBean
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

//        设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl(null);         // 禁用登录页面重定向
        shiroFilterFactoryBean.setUnauthorizedUrl(null);  // 禁用未授权页面重定向
        // 自定义过滤器
        Map<String, Filter> filters = new HashMap<>();
        filters.put("jwt", new JwtFilter());
        shiroFilterFactoryBean.setFilters(filters);
        //        设置shiro内置过滤器
        Map<String, String> filterMap = new LinkedHashMap<>();
        filterMap.put("/user/register","anon");
        filterMap.put("/user/login","anon");
//        主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截
        filterMap.put("/**","jwt");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);


        return shiroFilterFactoryBean;
    }





    /**
     * 开启注解方式控制访问url
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

}

  • 密码加盐
package com.example.test01.config;

/**
 * ClassName:SecurityConfig
 * Description:
 *

 */
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

@Configuration
@ConfigurationProperties(prefix = "app.security")
public class SecurityConfig {

    private String salt;

    // Getter 和 Setter 方法
    public String getSalt() {
        return salt;
    }

    public void setSalt(String salt) {
        this.salt = salt;
    }
}
  • redis的配置类
package com.example.test01.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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;



/**
 * redis配置
 *
 */
/**
 * redis序列化
 */
@Configuration
public class RedisConfig {
    @Bean(name = "redisTemplate")
    public RedisTemplate<String, Object> getRedisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
        // 设置序列化
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 配置redisTemplate
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
        RedisSerializer<?> stringSerializer = new StringRedisSerializer();
        // key序列化
        redisTemplate.setKeySerializer(stringSerializer);
        // value序列化
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        // Hash key序列化
        redisTemplate.setHashKeySerializer(stringSerializer);
        // Hash value序列化
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}


一些Util工具类

  • JwtUtil
package com.example.test01.utils;


import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;

@Slf4j
public class JwtUtil {

    private static final String SECRET_KEY = "your-secret-key";
    private static final long EXPIRATION_TIME = 1*24*60*60*1000; // 1天

    public static String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                .compact();
    }

    public static Claims parseToken(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();
    }

    // 验证 Token 是否有效
    public static boolean validateToken(String token) {
        try {
            parseToken(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

}

  • 密码加密的工具类PasswordUtil
package com.example.test01.utils;

import com.example.test01.config.SecurityConfig;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class PasswordUtil {

    @Autowired
    private SecurityConfig securityConfig;

    /**
     * 生成加盐后的密码
     *
     * @param password 明文密码
     * @param salt     盐值(通常是用户名或随机字符串)
     * @param hashIterations 散列次数
     * @return 加密后的密码
     */
    public  String encryptPassword(String password, int hashIterations) {
        // 获取盐值
        String salt = securityConfig.getSalt();
        // 使用 Shiro 的 Md5Hash 进行加密
        return new Md5Hash(password, salt, hashIterations).toHex();
    }

}
  • Redis存储的工具类
package com.example.test01.utils;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * redis 工具类
 **/
@Component
public class RedisUtil {

        // 使用jwt的过期时间毫秒
        private final long defaultTimeout = 1*24*60*60*1000;

        @Autowired
        private RedisTemplate<String, Object> redisTemplate;

        /**
         * 是否存在指定的key
         *
         * @param key
         * @return
         */
        public boolean hasKey(String key) {
            return Boolean.TRUE.equals(redisTemplate.hasKey(key));
        }

        /**
         * 删除指定的key
         *
         * @param key
         * @return
         */
        public boolean delete(String key) {
            return Boolean.TRUE.equals(redisTemplate.delete(key));
        }

        //- - - - - - - - - - - - - - - - - - - - -  String类型 - - - - - - - - - - - - - - - - - - - -
        /**
         * 根据key获取值
         *
         * @param key 键
         * @return 值
         */
        public Object get(String key) {
            return key == null ? null : redisTemplate.opsForValue().get(key);
        }

        /**
         * 将值放入缓存
         *
         * @param key   键
         * @param value 值
         * @return true成功 false 失败
         */
        public void set(String key, String value) {
            set(key, value, defaultTimeout);
        }

        /**
         * 将值放入缓存并设置时间
         *
         * @param key   键
         * @param value 值
         * @param time  时间(秒) -1为无期限
         * @return true成功 false 失败
         */
        public void set(String key, String value, long time) {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                redisTemplate.opsForValue().set(key, value, defaultTimeout, TimeUnit.SECONDS);
            }
        }

        //- - - - - - - - - - - - - - - - - - - - -  object类型 - - - - - - - - - - - - - - - - - - - -
        /**
         * 根据key读取数据
         */
        public Object getObject(final String key) {
            if (StringUtils.isBlank(key)) {
                return null;
            }
            try {
                return redisTemplate.opsForValue().get(key);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        /**
         * 写入数据
         */
        public boolean setObject(final String key, Object value) {
            if (StringUtils.isBlank(key)) {
                return false;
            }
            try {
                setObject(key, value , defaultTimeout);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
        }

        public boolean setObject(final String key, Object value, long time) {
            if (StringUtils.isBlank(key)) {
                return false;
            }
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                redisTemplate.opsForValue().set(key, value, defaultTimeout, TimeUnit.SECONDS);
            }
            return true;
        }
    }

  • 一个封装的异常的类
package com.example.test01.utils;

import com.example.test01.common.Result;
import org.springframework.http.HttpStatus;

import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSON;

import java.io.IOException;

/**
* ClassName:Utils
* Description:
*
*/
public class Utils {
   public static HttpServletResponse responseToken(ServletResponse response, String msg, int status) throws IOException {
       HttpServletResponse httpResponse = (HttpServletResponse) response;
//        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
//        httpResponse.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
       httpResponse.setCharacterEncoding("UTF-8");
       httpResponse.setContentType("application/json;charset=utf-8");
       //    httpResponse.sendError(R.TOKEN_EXPIRED, "登录超时,请重新登录!");
       httpResponse.getWriter().write(JSON.toJSONString(Result.error(status, msg)));
       return httpResponse;
   }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容