package com.jeeplus.gateway.excepiton;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jeeplus.common.constant.CacheNames;
import com.jeeplus.common.constant.ErrorConstants;
import com.jeeplus.common.redis.RedisUtils;
import com.jeeplus.gateway.security.TokenProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 认证失败处理类，返回401
 * Author: liugaofeng
 */
@Slf4j
@Component
public class JwtAuthenticationEntryPoint implements ServerAuthenticationEntryPoint {

    @Autowired
    private ObjectMapper mapper;


    @Override
    public Mono <Void> commence(ServerWebExchange exchange, AuthenticationException e) {
        //验证为未登陆状态会进入此方法，认证错误

        ServerHttpResponse response = exchange.getResponse ( );
        response.setStatusCode ( HttpStatus.FORBIDDEN );
        //验证为未登陆状态会进入此方法，认证错误
        String errMsg;
        String token = TokenProvider.resolveToken ( exchange.getRequest ( ) );
        if ( StrUtil.isEmpty ( token ) ) { // 没有token抛出的异常
            errMsg = ErrorConstants.LOGIN_ERROR_NOT_LOGIN_IN;
            response.setStatusCode ( HttpStatus.UNAUTHORIZED );
        } else { // token过期抛出的异常
            Object accessTokenObj = RedisUtils.getInstance ( ).get ( CacheNames.USER_CACHE_TOKEN, token );
            if ( accessTokenObj != null && accessTokenObj.toString ( ).equals ( "kickOut" ) ) {
                RedisUtils.getInstance ( ).delete ( CacheNames.USER_CACHE_TOKEN, token );
                RedisUtils.getInstance ( ).delete ( CacheNames.USER_CACHE_ONLINE_USERS, token );
                errMsg = ErrorConstants.LOGIN_ERROR__KICK_OUT_LOGGED_IN_ELSEWHERE;
            } else {
                errMsg = ErrorConstants.LOGIN_ERROR_EXPIRED;
            }
            response.setStatusCode ( HttpStatus.REQUEST_TIMEOUT );
        }
        response.getHeaders ( ).setContentType ( MediaType.APPLICATION_JSON_UTF8 );
        log.error ( errMsg );
        try {
            DataBuffer buffer = response.bufferFactory ( ).wrap ( mapper.writeValueAsBytes ( errMsg ) );
            return response.writeWith ( Mono.just ( buffer ) ).doOnError ( (error) -> {
                DataBufferUtils.release ( buffer );
            } );
        } catch (JsonProcessingException var5) {
            return Mono.error ( var5 );
        }
    }
}
