package com.ningdatech.carapi.user.security.auth.password;

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

import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;

/**
 * @Author LiuXinXin
 * @Date 2020/8/3 8:46 下午
 * @Version 1.0
 **/

public class UsernamePasswordAuthFilter extends AbstractAuthenticationProcessingFilter {

    private String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCAPhUV8sdOC5MB0m6qHAIJfI0vhkO+wZpO8srcmiMjbzCoaCSznlxZKLVv8MXMB5fgEHqTlrXThZlmCXHJRdZvIpBLNCYu5dd8T0NlmxuioiOVH3dU7Cd1a78B901oZ0NJ5TdcmtQQQQNIq/eKdeOpb+x9NGCLBy7vaOJtYYPTKQIDAQAB";

    private String privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAIA+FRXyx04LkwHSbqocAgl8jS+GQ77Bmk7yytyaIyNvMKhoJLOeXFkotW/wxcwHl+AQepOWtdOFmWYJcclF1m8ikEs0Ji7l13xPQ2WbG6KiI5Ufd1TsJ3VrvwH3TWhnQ0nlN1ya1BBBA0ir94p146lv7H00YIsHLu9o4m1hg9MpAgMBAAECgYBdgueFNZ62/iGX9oXTbNDfcf7RZKoJcsq+PrRF3+83a2CjrCz2/MaCDPkgQwU4HWFVdS6sZ/z13Dla+hAKn+4X2v2pL3ryrcjlY35yreB6NlCjbsRbEACZEvhaps/taLu4IkZ/CQ6msCz8XHkBOMlWDF36kIxS3BFRmu3mWjHCcQJBAMAfZfKZxWX6lJBWLSy3QhV8jIo9+e+kk4VQRZUXgLJf1IwkxcHMmp4OSgcJp5do1YcoBlPQNdaWta0bt7TQL0cCQQCq4X+jc8Ikn/fxeeIpE75CqveHiF86KU7HKVfpjqiZATIeIbBe8eeC1pXlgX6TmMTWFQSRHWVzmVSwRaRhuYIPAkBd5jquksdu60T3MpdLtpm+5KvP2TCyFq7fRndrwhvtknbQtBxPdw/O1k8KF4bosp1CPKazCh12LxzGabikz+d7AkA0iKbo5UmmYNelEUeKQVuYu17l9/LuuoxRhlBUqVsDzu5NfSXvyobWHopuyGTVk33QIx4ITvVFmLoEhySGNrXZAkBktQR+kMStI0SlcMKYFKmQXu78W97p8soVvhP1AndvPiI9keO3UxO7cUjcPRROmcGUU39yGHYlJvu1Krj6+GI1";

    private boolean postOnly = true;

    private final String SMS_VERIFICATION_CODE_FEILD = "verificationCode";

    // ~ Constructors
    // ===================================================================================================

    public UsernamePasswordAuthFilter(String processingUrl) {
        super(new AntPathRequestMatcher(processingUrl, "POST"));
    }
    // ~ Methods
    // ========================================================================================================

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
        throws AuthenticationException {

        if (postOnly && !HttpMethod.POST.toString().equals(request.getMethod())) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        RSA rsa = new RSA(privateKey, publicKey);
        String usernameParameter = "username";
        String username = request.getParameter(usernameParameter);
        // 将获取到的经过RSA公钥加密后的用户名解密
        String userName = rsa.decryptStr(username, KeyType.PrivateKey);

        String passwordParameter = "password";
        String password = request.getParameter(passwordParameter);
        // 将获取到的经过RSA公钥加密后的密码解密
        String pwd = rsa.decryptStr(password, KeyType.PrivateKey);
        String verificationCode = request.getParameter(SMS_VERIFICATION_CODE_FEILD);
        // 将获取到的经过RSA公钥加密后的验证码解密
        String verifyCode = rsa.decryptStr(verificationCode, KeyType.PrivateKey);

        if (StringUtils.isBlank(userName) || StringUtils.isBlank(pwd)) {
            throw new UsernameNotFoundException("帐号密码不能为空!");
        }
        userName = userName.trim();
        pwd = pwd.trim();
        verifyCode = verifyCode.trim();

        try {
            UsernamePasswordAuthToken authRequest = new UsernamePasswordAuthToken(userName, pwd, verifyCode);
            // Allow subclasses to set the "details" property
            setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        } catch (AuthenticationException e) {
            throw e;
        } catch (Exception e) {
            throw new InternalAuthenticationServiceException(e.getMessage(), e);
        }
    }

    protected void setDetails(HttpServletRequest request, UsernamePasswordAuthToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }
}
