package io.geekidea.springbootplus.framework.shiro.signature;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.util.WebUtils;

/**
 * shiro 用户签名认证
 * @Author luozh
 * @Date 2022年04月14日 16:43
 * @Version 1.0
 */
@Slf4j
public class SignatureAuthFilter extends AuthenticatingFilter {

    private static final String AUTHORIZATION = "Authorization";

    private ApplicationService applicationService;

    public SignatureAuthFilter(@NotNull ApplicationService applicationService) {
        if (applicationService == null) {
            throw new IllegalArgumentException("application service must not be null");
        }

        this.applicationService = applicationService;
    }

    @Override
    protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {

        ShiroHttpServletRequest ShiroHttpServletRequest = (ShiroHttpServletRequest) servletRequest;

        HttpServletRequest request =
                (HttpServletRequest) ShiroHttpServletRequest.getRequest();

        String authorization = request.getHeader(AUTHORIZATION);
        if (StringUtils.isBlank(authorization)) {
            throw new AuthenticationException("token不能为空");
        }
        // 校验Signature是否完整 合规
        if (!authorization.startsWith("WECLOUD-IM AppKey")) {
            throw new AuthenticationException("token错误");
        }
        if (!authorization.contains(", Signature:")) {
            throw new AuthenticationException("token 未包含签名信息");
        }

        String appKey = getAppKeyFromAuthorization(authorization);
        String clientSignature = getSignatureFromAuthorization(authorization);

        // 校验通过 获取并校验Application信息
        Application application = applicationService.getApplication(appKey);
        if (application == null) {
            throw new AuthenticationException("application does not exist");
        }

        if (!application.isActive()) {
            throw new AuthenticationException("application is unavailable");
        }
        Long appId = application.getId();
        String appSecret = application.getAppSecret();
        SignatureChecker.check(request, clientSignature, appSecret);

        // 构建SignatureAuthToken
        return new SignatureAuthToken(appKey, appId);
    }

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        String url = WebUtils.toHttp(request).getRequestURI();
        log.info("isAccessAllowed url:{}", url);
        if (this.isLoginRequest(request, response)) {
            return true;
        }
        boolean allowed = false;
        try {
            allowed = executeLogin(request, response);
        } catch (IllegalStateException e) { //not found any token
            log.error("Token不能为空", e);
        } catch (Exception e) {
            log.error("访问错误", e);
        }
        return true;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        return false;
    }

    private String getAppKeyFromAuthorization(String authorization) {
        // 处理token
        String[] tokenInfo = authorization.split(",");
        // appkey 格式是固定的，直接替换
        return tokenInfo[0].replace("WECLOUD-IM AppKey:", "").trim();
    }

    private String getSignatureFromAuthorization(String authorization) {
// 处理token
        String[] tokenInfo = authorization.split(",");
        // 客户端传入的签名信息
        return tokenInfo[1].replace("Signature:", "").trim();
    }

}
