package com.njcn.product.auth.security.provider;

import com.njcn.common.utils.sm.Sm4Utils;
import com.njcn.product.auth.pojo.bo.BusinessUser;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;

/**
 * @author hongawen
 * @version 1.0.0
 * @date 2021年06月08日 15:43
 */
@Slf4j
@Component
@AllArgsConstructor
public class Sm4AuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

    private final UserDetailsService userDetailsService;


    /**
     * 校验密码有效性.
     *
     * @param userDetails    用户详细信息
     * @param authentication 用户登录的密码
     * @throws AuthenticationException .
     */
    @Override
    protected void additionalAuthenticationChecks(
            UserDetails userDetails, UsernamePasswordAuthenticationToken authentication)
            throws AuthenticationException {
        if (authentication.getCredentials() == null) {
            logger.debug("Authentication failed: no credentials provided");

            throw new BadCredentialsException(messages.getMessage(
                    "AbstractUserDetailsAuthenticationProvider.badCredentials",
                    "Bad credentials"));
        }

        String presentedPassword = authentication.getCredentials().toString();
        BusinessUser businessUser = (BusinessUser)userDetails;
        String secretKey = businessUser.getSecretKey();
        Sm4Utils sm4 = new Sm4Utils(secretKey);
        //SM4加密密码
        String sm4PwdOnce = sm4.encryptData_ECB(presentedPassword);
        //SM4加密(密码+工作秘钥）
        String sm4PwdTwice = sm4.encryptData_ECB(sm4PwdOnce + secretKey);
        if(!businessUser.getPassword().equalsIgnoreCase(sm4PwdTwice)){
            throw new BadCredentialsException(messages.getMessage(
                    "AbstractUserDetailsAuthenticationProvider.badCredentials",
                    businessUser.getUsername()));
        }
    }

    /**
     * 获取用户
     *
     * @param username       用户名
     * @param authentication 认证token
     * @throws AuthenticationException .
     */
    @Override
    protected UserDetails retrieveUser(
            String username, UsernamePasswordAuthenticationToken authentication)
            throws AuthenticationException {
        UserDetails loadedUser = userDetailsService.loadUserByUsername(username);
        if (loadedUser == null) {
            throw new InternalAuthenticationServiceException(
                    "UserDetailsService returned null, which is an interface contract violation");
        }
        return loadedUser;
    }


    /**
     * 授权持久化.
     */
    @Override
    protected Authentication createSuccessAuthentication(Object principal,
                                                         Authentication authentication, UserDetails user) {
        return super.createSuccessAuthentication(principal, authentication, user);
    }
}