/*
 * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.tykj.workflowcore.user.authencation.filter;

import com.tykj.workflowcore.base.result.ApiException;
import com.tykj.workflowcore.user.authencation.token.JwtAuthencationToken;
import com.tykj.workflowcore.user.pojo.StorageKey;
import com.tykj.workflowcore.user.pojo.User;
import com.tykj.workflowcore.user.util.CipherUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
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 org.springframework.util.StringUtils;

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

/**
 * Jwt凭证验证拦截器
 *
 * @author HuangXiahao
 * @version V1.0
 * @class CustomJWTAuthenticationFilter
 * @packageName com.example.personnelmanager.common.authencation.filter
 * @data 2020/6/13
 **/
public class CustomJwtAuthenticationFilter extends
        AbstractAuthenticationProcessingFilter {

    public static final String JWT_KEY = "jwt";

    /**
     * Jwt公钥路径
     */
    String jwtFilePath;

    public CustomJwtAuthenticationFilter() {
        //设置用户接口的路径以及访问方式
        super(new AntPathRequestMatcher("/user/login", "GET"));
    }

    /***
     * 在这个方法中执行验证操作
     * @param request
     * @param response
     * @Return : org.springframework.security.core.Authentication
    */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {
        JwtAuthencationToken authRequest ;
        User userByJwt;
        //如果请求头中没有jwt凭证的话说明不应该使用该类进行验证，直接报错
        if (!StringUtils.isEmpty(request.getHeader(JWT_KEY))) {
            //通过请求头获取jwt凭证中的用户信息
            userByJwt = getuserbyjwt(request);
            authRequest = new JwtAuthencationToken(
                    userByJwt);
            //为用于验证的用户注入session信息
            setDetails(request, authRequest);
            //进行验证
            return getAuthenticationManager().authenticate(authRequest);
        } else {
            throw new ApiException("未设置token");
        }

    }

    /***
     * 为用户注入session信息
     * @param request
     * @param authRequest
     * @Return : void
    */
    protected void setDetails(HttpServletRequest request,
                              JwtAuthencationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }

    /***
     * 通过请求头获取请求头中的用户信息
     *
     * @param request
     * @Return : com.example.personnelmanager.entity.User
    */
    public User getuserbyjwt(HttpServletRequest request) {
        StorageKey storageKey = new StorageKey();
        String rsaPrivateKey = storageKey.getRsaPrivateKey();
        String signPublicKey = storageKey.getSignPublicKey();
            String jwt = request.getHeader("jwt");
        try {
            String decrypt = CipherUtil.decrypt(jwt, CipherUtil.string2PrivateKey(rsaPrivateKey));
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(CipherUtil.string2PublicKey(signPublicKey)).parseClaimsJws(decrypt);
            logger.info("接收到的用户信息为："+claimsJws.getBody());
            User userRight = new User();
            Claims body = claimsJws.getBody();
            userRight.setUsername((String) body.get("username"));
            userRight.setPhone((String) body.get("phone"));
            return userRight;
        }catch (Exception e){
            logger.error("用户凭证无效");
            throw new UsernameNotFoundException("用户凭证无效");
        }
    }
}
