springboot项目中,将在拦截器中解析token得到的信息传给Service层

ThreadLocal并不是一个Thread,而是Thread的局部变量

ThreadLocal为每个线程单独提供一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。

可以打印当前线程的id来验证拦截器,controller和service是否在同一个线程内执行

System.out.println(Thread.currentThread().getId());

 然后再发送一次请求

可以看到,发起的每一个请求都是一个单独的线程 ,满足每个线程都是单独的一份存储空间。

就可以在拦截器中将从token获取到的用户id存放到ThreadLocal中去,然后在service层拿出id,然后将这个id添加到数据库中。

ThreadLocal常用方法

public void set(T value)设置当前线程局部变量的值
public T get()返回当前线程所对应的线程局部变量的值
public void remove()移除当前线程的线程局部变量

封装ThreadLocal便于代码的维护

package com.sky.context;

/**
 * ThreadLocal为每个线程单独提供一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
 * 将ThreadLocal进行封装,便于代码的维护和迭代
 */
public class BaseContext {

    public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    public static void setCurrentId(Long id) {
        threadLocal.set(id);
    }

    public static Long getCurrentId() {
        return threadLocal.get();
    }

    public static void removeCurrentId() {
        threadLocal.remove();
    }

}

在拦截器中将解析后的token载荷中的用户id存放在ThreadLocal中,然后在service中取出

package com.sky.interceptor;

import com.sky.constant.JwtClaimsConstant;
import com.sky.context.BaseContext;
import com.sky.properties.JwtProperties;
import com.sky.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * jwt令牌校验的拦截器
 */
@Component
@Slf4j
public class JwtTokenAdminInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtProperties jwtProperties;

    /**
     * 校验jwt
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //打印当前线程的id
        //System.out.println(Thread.currentThread().getId());

        //判断当前拦截到的是Controller的方法还是其他资源
        if (!(handler instanceof HandlerMethod)) {
            //当前拦截到的不是动态方法,直接放行
            return true;
        }

        //1、从请求头中获取令牌
        String token = request.getHeader(jwtProperties.getAdminTokenName());

        //2、校验令牌
        try {
            log.info("jwt校验:{}", token);
            Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
            Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
            log.info("当前员工id:", empId);
            //在拦截器中,将用户id放入ThreadLocal中
            BaseContext.setCurrentId(empId);
            //3、通过,放行
            return true;
        } catch (Exception ex) {
            //4、不通过,响应401状态码
            response.setStatus(401);
            return false;
        }
    }
}
package com.sky.service.impl;

import com.sky.constant.MessageConstant;
import com.sky.constant.PasswordConstant;
import com.sky.constant.StatusConstant;
import com.sky.context.BaseContext;
import com.sky.dto.EmployeeDTO;
import com.sky.dto.EmployeeLoginDTO;
import com.sky.entity.Employee;
import com.sky.exception.AccountLockedException;
import com.sky.exception.AccountNotFoundException;
import com.sky.exception.PasswordErrorException;
import com.sky.mapper.EmployeeMapper;
import com.sky.service.EmployeeService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import sun.security.provider.MD5;

import java.time.LocalDateTime;

@Service
public class EmployeeServiceImpl implements EmployeeService {

    @Autowired
    private EmployeeMapper employeeMapper;

    /**
     * 员工登录
     *
     * @param employeeLoginDTO
     * @return
     */
    public Employee login(EmployeeLoginDTO employeeLoginDTO) {
        String username = employeeLoginDTO.getUsername();
        String password = employeeLoginDTO.getPassword();

        //1、根据用户名查询数据库中的数据
        Employee employee = employeeMapper.getByUsername(username);

        //2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)
        if (employee == null) {
            //账号不存在
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }

        //密码比对
        //对前端传过来的明文密码进行md5加密
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        System.out.println(password);
        if (!password.equals(employee.getPassword())) {
            //密码错误
            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }

        if (employee.getStatus() == StatusConstant.DISABLE) {
            //账号被锁定
            throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
        }

        //3、返回实体对象
        return employee;
    }

    /**
     * 新增员工
     * @param employeeDTO
     */
    public void save(EmployeeDTO employeeDTO) {
        //System.out.println(Thread.currentThread().getId());
        //在mapper添加员工时,推荐使用entity
        //在此处根据employeeDTO设置Employee的属性,一个一个设置会导致代码太繁琐,使用对象属性拷贝
        Employee employee = new Employee();
        BeanUtils.copyProperties(employeeDTO,employee);

        //设置员工账号状态,默认为可用状态
        employee.setStatus(StatusConstant.ENABLE);

        //设置密码,密码默认为123456
        employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));

        //设置创建时间和修改时间
        employee.setCreateTime(LocalDateTime.now());
        employee.setUpdateTime(LocalDateTime.now());

        //从ThreadLocal存储空间中使用BaseContext.getCurrentId(),将id取出来
        employee.setCreateUser(BaseContext.getCurrentId());
        employee.setUpdateUser(BaseContext.getCurrentId());

        //将employee交给mapper
        employeeMapper.save(employee);



    }

}

Spring Boot项目,当用户成功登录后,你可以通过Spring Security库轻松地创建并设置Cookie,以便将其传递给浏览器。以下是简单的步骤: 1. 首先,在`SecurityConfig`配置类启用HttpSessionAuthenticationSuccessHandler,并自定义一个处理程序,比如`CustomAuthenticationSuccessHandler`,用于设置cookie: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // 其他授权规则... .formLogin() .successHandler(customAuthenticationSuccessHandler()); } private AuthenticationSuccessHandler customAuthenticationSuccessHandler() { return new CustomAuthenticationSuccessHandler(); } } ``` 2. 创建`CustomAuthenticationSuccessHandler`,在这里设置cookie: ```java @Component public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler { @Autowired private CookieSerializer cookieSerializer; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { // 创建一个包含用户名等信息的Principal对象 String username = authentication.getName(); // 创建Cookie对象 Cookie cookie = new HttpCookie("myCustomToken", cookieSerializer.serialize(username)); cookie.setMaxAge(60 * 60); // 设置有效期(单位:秒) cookie.setSecure(true); // 如果需要,设置为仅在HTTPS连接上发送 // 将Cookie添加到响应头 response.addCookie(cookie); // 可选:跳转至主页或其他页面 response.sendRedirect("/"); } } ``` 3. 定义CookieSerializer,这可以是一个自定义序列化器,将用户名等信息转换为字符串: ```java @Component public class CookieSerializer { public String serialize(Object principal) { if (principal instanceof UsernamePasswordAuthenticationToken) { UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) principal; Object credentials = token.getCredentials(); // 根据实际情况提取和处理用户名 return credentials.toString(); // 这里只是一个示例 } return null; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值