package org.springblade.common.auth.aspect;

import com.alibaba.fastjson.JSON;
import org.springblade.common.auth.permission.Admin;
import org.springblade.common.auth.support.AdminUserDTO;
import org.springblade.common.cache.CachesService;
import com.wn.common.tools.string.AccountValidatorUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.StringTokenizer;

/**
 * admin管理接口切面
 *
 * @author majunjie
 * @date 2019/5/11 10:42
 */
@Slf4j
@Aspect
@Component
public class AdminAspect {

    @Value("${admin.ip.whitelist.flag:false}")
    private Boolean whitelistSwitch;
    @Value("${admin.ip.whitelist:114.215.24.128;183.129.191.50;")
    private String ipWhitelist;

    @Autowired
    private CachesService cachesService;

    /**
     * 1、请求合法性校验（ip、header）
     * 2、把登录人信息放进对应参数中
     *
     * @param joinPoint
     * @param admin
     * @throws Throwable
     */
    @Around("@annotation(admin)")
    public Object doBefore(ProceedingJoinPoint joinPoint, Admin admin) throws Throwable {
        boolean illegal = true;
        //ip校验
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        if (whitelistSwitch) {
            //ip白名单校验
            String ipAddr = getIpAddr(request);
            StringTokenizer patterns = new StringTokenizer(ipWhitelist, ";");
            while (patterns.hasMoreTokens()) {
                if (ipAddr.equals(patterns.nextToken())) {
                    illegal = false;
                    log.info("admin访问内部接口，请求合理，ip：{}", ipAddr);
                    break;
                }
            }

            if (illegal) {
                log.warn("admin访问内部接口，非法请求，ip：{}", ipAddr);
                throw new RuntimeException("非法请求");
            }
        }

        Object[] args = joinPoint.getArgs();
        if (args != null) {
            for (int i = 0; i < args.length; i++) {
                //主动set Admin登录人信息
                Object arg = args[i];
                if (arg!=null && arg.getClass() == AdminUserDTO.class) {
                    args[i] = getAdminUser(request);
                    log.debug("获取admin登录人信息成功, {}", JSON.toJSONString(args[i]));
                    break;
                }
            }
        }
        //用改变后的参数执行目标方法
        return joinPoint.proceed(args);
    }

    /**
     * 获取admin登录人信息
     *
     * @param request
     * @return
     */
    public AdminUserDTO getAdminUser(HttpServletRequest request) {
        String loginUserKey = request.getHeader("adminLoginUserKey");
        String value = cachesService.getStringFromCache(loginUserKey, "");
        if (StringUtils.isBlank(value)) {
            throw new RuntimeException("非法请求");
        }
        return JSON.parseObject(value, AdminUserDTO.class);
    }

    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个ip值，第一个ip才是真实ip
            if (ip.indexOf(",") != -1) {
                ip = ip.split(",")[0];
                if (StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
                    if (!AccountValidatorUtils.isIPAddr(ip)) {
                        ip = null;
                    }
                }
            }
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

}