spring boot 配置拦截器验证使用 token 登录

1、自定义登录注解

package io.xiongdi.annotation;

import java.lang.annotation.*;

/**
 * @author wujiaxing
 * @date 2019-07-12
 * 登录校验
 */
@Target(ElementType.METHOD)
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Login {
}

2、创建 token 实体类

package io.xiongdi.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Builder;
import lombok.Data;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * 用户token
 * @author wujiaxing
 * @date ${2019-6-30}
 */
@Data
@TableName("tb_token")
@Builder
public class TokenEntity implements Serializable {

    private static final long serialVersionUID = 5584132314624077161L;

    public TokenEntity(){}

    public TokenEntity(long userId, String token, LocalDateTime expireTime, LocalDateTime updateTime) {
        this.userId = userId;
        this.token = token;
        this.expireTime = expireTime;
        this.updateTime = updateTime;
    }

    /**
     *  用户ID
     */
    @TableId(type = IdType.INPUT)
    private long userId;
    /**
     * token
     */
    private String token;
    /**
     *  过期时间
     */
    private LocalDateTime expireTime;
    /**
     *  修改时间
     */
    private LocalDateTime updateTime;
}

3、创建处理 token 的接口方法

package io.xiongdi.service;

import com.baomidou.mybatisplus.extension.service.IService;
import io.xiongdi.entity.TokenEntity;

/**
 * token
 * @author wujiaxing
 * @date 2019-06-30
 */
public interface TokenService extends IService<TokenEntity> {

    /**
     * <p>
     *     根据请求token查询token信息
     * </p>
     * @param token
     * @return
     */
    TokenEntity queryByToken(String token);

    /**
     *  创建token
     * @param userId 用户ID
     * @return 返回token信息
     */
    TokenEntity createToken(long userId);

    /**
     * 设置token过期
     * @param userId 用户ID
     */
    void expireToken(long userId);
}
package io.xiongdi.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.xiongdi.dao.TokenDao;
import io.xiongdi.entity.TokenEntity;
import io.xiongdi.service.TokenService;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.UUID;

/**
 * @author wujiaxing
 * @date 2019-07-08
 */
@Service("tokenService")
public class TokenServiceImpl extends ServiceImpl<TokenDao, TokenEntity> implements TokenService {

    /**
     * 12 小时过期 单位:毫秒
     */
    private final static int EXPIRE = 3600 * 12 * 1000;

    /**
     *  根据请求头的token查询数据库对应的token信息
     * @param token
     * @return
     */
    @Override
    public TokenEntity queryByToken(String token) {
        return this.getOne(new QueryWrapper<TokenEntity>().eq("token", token));
    }

    @Override
    public TokenEntity createToken(long userId) {
        // 得到当前时间
        LocalDateTime now = LocalDateTime.now();
        // 根据过期时间加上当前时间,得到token的有效期
        long indate = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli() + EXPIRE;
        LocalDateTime tokenExpireDateTime = LocalDateTime.ofInstant(new Date(indate).toInstant(), ZoneId.systemDefault());
        // 生成token
        String token = generateToken();
        // 创建实体对象
        TokenEntity tokenEntity = TokenEntity.builder().expireTime(tokenExpireDateTime).userId(userId).token(token).updateTime(now).build();
        // 放入数据库保存
        this.saveOrUpdate(tokenEntity);
        return tokenEntity;
    }

    /**
     *  生成token
     * @return
     */
    private String generateToken() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    @Override
    public void expireToken(long userId) {
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        TokenEntity tokenEntity = TokenEntity.builder().userId(userId).expireTime(now).updateTime(now).build();
        this.saveOrUpdate(tokenEntity);
    }
}

4、创建拦截器

package io.xiongdi.interceptor;

import io.xiongdi.annotation.Login;
import io.xiongdi.common.exception.XDException;
import io.xiongdi.common.utils.ResultType;
import io.xiongdi.entity.TokenEntity;
import io.xiongdi.service.TokenService;
import org.apache.commons.lang.StringUtils;
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;
import java.time.LocalDateTime;

/**
 * 权限(token)验证
 * @author wujiaxing
 * @date 2019-06-30
 */
@Component
public class AuthorizationInterceptor implements HandlerInterceptor {

    @Autowired
    private TokenService tokenService;

    public final static String USER_KEY = "userId";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Login annotation;
        // 如果处理对象是一个处理方法,则获取到方法上的注解
        if (handler instanceof HandlerMethod) {
            annotation = ((HandlerMethod)handler).getMethodAnnotation(Login.class);
        // 否则直接放过拦截的请求
        } else {
            return true;
        }
        // 说明此方法没有Login注解
        if (annotation == null) {
            return true;
        }

        // 从请求头获取token
        String token = request.getHeader("token");

        // 如果请求头没有token,则从请求参数中取
        if (StringUtils.isBlank(token)) {
            token = request.getParameter("token");
        }
        // 如果还是没有token,则抛异常
        if (StringUtils.isBlank(token)) {
           throw new XDException(ResultType.TOKEN_NULL);
        }

        // 查询token信息
        TokenEntity tokenEntity = tokenService.queryByToken(token);

        // 如果token信息是否为null或是否过期,则抛异常
        if (tokenEntity == null || tokenEntity.getExpireTime().isBefore(LocalDateTime.now())) {
            throw new XDException(ResultType.TOKEN_EXPIRE);
        }

        // 否则,存入request作用域,后续根据userId,获取用户信息
        request.setAttribute(USER_KEY, tokenEntity.getUserId());

        return true;
    }
}

5、将拦截器配置给 spring boot

package io.xiongdi.config;

import io.xiongdi.interceptor.AuthorizationInterceptor;
import io.xiongdi.resolver.LoginUserHandlerMethodArgumentResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

/**
 * @author wujiaxing
 * <p>
 *     此配置类可配置拦截器、参数解析器、返回值解析器、跨域支持等等
 * </p>
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private AuthorizationInterceptor authorizationInterceptor;
    @Autowired
    private LoginUserHandlerMethodArgumentResolver loginUserHandlerMethodArgumentResolver;

    /**
     * 拦截器配置
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authorizationInterceptor).addPathPatterns("/api/**");
    }

    /**
     * 跨域支持配置
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowCredentials(true).allowedOrigins("*").allowedMethods("GET", "PUT", "DELETE", "POST", "OPTIONS").maxAge(3600);
    }

    /**
     * 参数解析配置
     * @param resolvers
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(loginUserHandlerMethodArgumentResolver);
    }
}

6、配置已经好了,可以开始测试

原文地址:https://www.cnblogs.com/wujiaxing/p/11180062.html

时间: 2024-08-29 11:37:02

spring boot 配置拦截器验证使用 token 登录的相关文章

【第四十章】Spring Boot 自定义拦截器

1.首先编写拦截器代码 package com.sarnath.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Service; import org.springframework.web.servlet.HandlerInterceptor; import

Spring Boot整合拦截器

过滤器和监听器都属于Servlet 的api,还可以使用 Spring 提供的拦截器(HandlerInterceptor)进行改更精细的控制. 原文地址:https://www.cnblogs.com/natian-ws/p/10823072.html

Spring Boot之拦截器与过滤器(完整版)

作者:liuxiaopeng 链接:http://www.cnblogs.com/paddix 作者:蓝精灵lx原文:https://blog.csdn.net/liuxiao723846/article/details/80656492 参考以上两位作者文章链接进行实验整合,仅供学习交流 一.拦截器与过滤器 先理解一下AOP的概念,AOP不是一种具体的技术,而是一种编程思想. 在面向对象编程的过程中,我们很容易通过继承.多态来解决纵向扩展. 但是对于横向的功能,比如,在所有的service方法

spring boot 添加拦截器

构建一个spring boot项目. 添加拦截器需要添加一个configuration @Configuration @ComponentScan(basePackageClasses = Application.class, useDefaultFilters = true) public class ServletContextConfig extends WebMvcConfigurationSupport { 为了方便扫描位置,我们可以写一个接口或者入口类Application放置于最外

(021)Spring Boot之拦截器HandlerInterceptor

 拦截器的使用步骤: 第一步,实现HandlerInterceptor接口,该接口有三个方法preHandle .postHandle .afterCompletion (1)preHandle在controller执行之前调用 (2)postHandle在controller执行之后,页面渲染之前调用 (3)afterCompletion在页面渲染之后调用,一般用于资源清理操作 第二步,继承WebMvcConfigurationSupport或者实现WebMvcConfigurer,重写他们的

Spring boot 自定义拦截器

1.新建一个类实现HandlerInterceptor接口,重写接口的方法 1 package com.zpark.interceptor; 2 3 import com.zpark.tools.Constants; 4 import com.zpark..tools.utils.EmptyUtils; 5 import org.slf4j.Logger; 6 import org.slf4j.LoggerFactory; 7 import org.slf4j.MDC; 8 import org

spring原拦截器配置与新命名空间mvc:interceptors配置拦截器对照与注意事项

原先,我们是这么配置拦截器的 <bean id="openSessionInViewInterceptor"class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor"> <property name="sessionFactory" ref="sessionFactory" /> </bean>

spring原拦截器配置与新命名空间mvc:interceptors配置拦截器对比与注意事项

原先,我们是这么配置拦截器的 <bean id="openSessionInViewInterceptor"class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor"> <property name="sessionFactory" ref="sessionFactory" /> </bean>

7.添加基于Spring的WebService拦截器

客户端拦截器: public class AccountInterceptor extends AbstractPhaseInterceptor<SoapMessage>{ private String name; private String password; public AccountInterceptor(String name,String password) { //Phase值决定了拦截器什么时候拦截到消息 //PRE_PROTOCOL准备请求时拦截 super(Phase.P