微服务的登录校验(gateway过滤器or拦截器实现)

问题来源

在做找房微服务的时候,一般只有登录的用户能够预约房源操作,或者修改资料等密码操作,管理员也需要登录的情况下才能对房源进行管理上架、添加等操作。

假如我们没一个方法都分别对其权限鉴定,用户判断是否登录,那么一个团队的开发每一个成员涉及到需要鉴权或者判断用户是否登录的情况,都需要写一套相同的代码,或者调用相同的接口,可是这些实际上应该是与本次逻辑不相干的代码,开发小组的成员应该更专注于本次需要实现的逻辑与功能。

通过接口调用,或者写一套相同的鉴权、判断用户是否登录的方法,极大的干扰开发的进度,也及其不利于后续的迭代开发。例子:如果鉴权、登录判断逻辑或者接口方法发生改变,那么一套系统中很多部分代码都需要修改代码。

理解下文首先要清楚一些最基本的概念

过滤器:

过滤器依赖servlet容器。过滤所有请求。可以在对服务器方法请求前后进行一些操作,能够决定是否放行请求。例如:字串编码,提前在request中设置一些参数等。

拦截器:

拦截器依赖web框架,springMVC中依赖的mvc框架,所以它能够spring依赖注入DI操作。实现上是反射机制实现的。对某个service方法前或后执行某部分逻辑。能够决定请求是否能被放行。功能类似过滤器

执行顺序

图片来源:https://www.cnblogs.com/juanzila/p/11276067.html
在这里插入图片描述
在这里插入图片描述

解决方法

第一种:过滤器方法实现。

本项目中遵循restful原则,GET请求一般为查询资源,POST,PUT,DELETE为修改添加资源操作。

gateway依赖

<!--gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

编写过滤器

@Component
public class MygateWayFilter implements GlobalFilter, Ordered {

    @Autowired
    JwtUtil jwtUtil;

    @Autowired
    RedisTemplate redisTemplate;

    /**
     * 可以用于验证用户登录状态,设置某部分请求信息等。
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String uri = request.getURI().toString();
        //判断当前是什么类型请求GET请求直接放行
        if (StringUtils.equals(request.getMethod().toString(), "GET")){
            return chain.filter(exchange);
        }
        //不是GET,判断是不是登录
        if (uri.contains("login")){
            return chain.filter(exchange);
        }
        //如果不是GET请求,判断是否已经登录,token是否过期
        //获取cookie中的token令牌
        MultiValueMap<String, HttpCookie> multiValueMap = exchange.getRequest().getCookies();
        List<HttpCookie> cookies =  multiValueMap.get("token");
        if (cookies != null && cookies.size() != 0) {
            String token = cookies.get(0).getValue();
            //token为空说明未登录,不放行
            if (StringUtils.isBlank(token)){
                response.setStatusCode(HttpStatus.FORBIDDEN);
                return response.setComplete();
            }
            //token not null
            try {
                Claims claims = jwtUtil.parseJWT(token);
                String userId = claims.getId();
                Object userLoginIP = redisTemplate.opsForValue().get("token_"+userId);
                //判断是否被token盗用
                if (!StringUtils.equals(String.valueOf(userLoginIP), CusAccessObjectUtil.getIpAddress(request))){
                    response.setStatusCode(HttpStatus.FORBIDDEN);
                    return response.setComplete();
                }
                return chain.filter(exchange);
            }catch (Exception e){
                e.printStackTrace();
                response.setStatusCode(HttpStatus.FORBIDDEN);
                return response.setComplete();
            }
        }
        //没有cookie不放行
        response.setStatusCode(HttpStatus.FORBIDDEN);
        return response.setComplete();
    }

    @Override
    public int getOrder() {
        return 0;
    }

}

第二种:拦截器方法实现。(推荐单服务、单系统情况)

第一步:编写拦截器类
import com.zxf.service.UserService;
import com.zxf.serviceResult.ServiceResult;
import com.zxf.utils.CookieUtils;
import com.zxf.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

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

/**
 * 登录判断拦截
 */
@Component
public class MyInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    JwtUtil jwtUtil;

    @Value("${token_name}")
    private String TOKENNAME;

    @Value("${redirectURL}")
    private String redirectURL;

    @Autowired
    UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = CookieUtils.getCookieValue(request, TOKENNAME);
        String requestURL = request.getRequestURI();
        System.out.println(requestURL);
        //不存在token,未登录的情况下不放行,直接跳转到登录页面,跳转到登录页面以后在跳转回当前页面
        if (token == null){
            response.sendRedirect(redirectURL+"?url="+requestURL);
            return false;
        }
        //执行判断是否存在盗用,或者过期
        ServiceResult serviceResult = userService.checkToken(token, request);
        if (serviceResult.getStatus() != ServiceResult.Status.SUCCESS.getCode()){
            response.sendRedirect(redirectURL+"?url="+requestURL);
            return false;
        }
        return true;
    }
}
第二步:编写拦截器配置类
@Configuration
public class MyInterceptorConfig implements WebMvcConfigurer {

    @Autowired
    private MyInterceptor myInterceptor;

    /**
     * 配置拦截的请求,与不拦截的请求
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/**/login", "/**/loginPage", "/**/static/**"); //这些请求不拦截

    }

}
  • 8
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
Spring Boot拦截器是一种用于在请求到达目标方法之前或之后执行一些操作的机制。在实现登录校验时,可以使用拦截器拦截请求,并进行登录状态的验证。 首先,需要编写一个拦截器类来实现登录校验的逻辑。拦截器类需要继承HandlerInterceptorAdapter,并重写preHandle方法。在preHandle方法中,可以获取到请求的信息,如请求路径和参数。根据业务需要,可以从请求中获取登录状态信息,进行验证。 其次,需要配置拦截器类生效的路径。在Spring Boot中,可以通过配置类或注解来配置拦截器类。可以使用@Configuration注解标注一个配置类,并通过implements WebMvcConfigurer接口来添加拦截器。 在配置类中,可以通过重写addInterceptors方法来配置拦截器。将拦截器对象添加到InterceptorRegistry中,并设置拦截的路径。可以使用addPathPatterns方法来设置拦截的路径模式,如"/user/*"表示拦截以/user/开头的路径。 在拦截器生效后,当发起请求时,拦截器拦截请求并调用preHandle方法进行登录校验。如果登录状态验证失败,可以根据业务需要进行处理,如返回错误信息或进行重定向。 需要注意的是,拦截器拦截的是请求,而不是方法。也就是说,拦截器会在请求到达目标方法之前执行,但不会影响目标方法的执行。如果需要在拦截器中进行一些后续操作,可以使用postHandle和afterCompletion方法。 通过使用Spring Boot拦截器校验登录,可以在请求到达目标方法之前进行登录状态的验证,确保只有已登录用户才能访问敏感接口或页面,提高系统的安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值