2021-10-15

过滤器实现第三方接口鉴权访问

前台将设定好的secret和timestamp根据设定好的算法进行加密生成sinature,将timestamp和signature传到后台,后台拿到timestamp将其与定义的secret一起进行加密得到加密值,将加密值与前台传递的signature进行比较看是否相等,并以此作为放行凭证。(注:此处定义了一个ip白名单,只有在名单里的才能进行访问验证)

pom.xml

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- devtools -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
        </dependency>
    </dependencies>

application.properties

# ip白名单(多个使用逗号分隔)在此名单内的ip才可以访问
permitted-ips = 192.168.125.118, 169.254.205.177, 169.254.133.33, 10.8.109.31, 0:0:0:0:0:0:0:1
# secret
secret = JustryDeng

utils.IpUtil

package com.sina.demo.utils;

import java.net.InetAddress;
import java.net.UnknownHostException;

import javax.servlet.http.HttpServletRequest;

/**
 * 功能描述: 获取登录的ip
 *
 * @Param:
 * @Return:
 * @Author: 方臭臭
 * @Date:
 */

public class IpUtil {

    public static String getIpAddr(HttpServletRequest request) {
        String ipAddress = null;
        try {
            ipAddress = request.getHeader("x-forwarded-for");
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getRemoteAddr();
                if (ipAddress.equals("127.0.0.1")) {
                    // 根据网卡取本机配置的IP
                    InetAddress inet = null;
                    try {
                        inet = InetAddress.getLocalHost();
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    }
                    ipAddress = inet.getHostAddress();
                }
            }

            // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割

            if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
                // = 15
                if (ipAddress.indexOf(",") > 0) {
                    ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                }
            }
        } catch (Exception e) {
            ipAddress="";
        }
        return ipAddress;
    }
}

utils.MDUtils

package com.sina.demo.utils;
import java.net.URLEncoder;
import java.util.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

/**
 * 功能描述: 加密工具类
 *
 * @Param:
 * @Return: encodeStr
 * @Author: 方留龙
 * @Date:
 */
public class MDUtils {


    public static final String ENCODE_TYPE_HMAC_SHA_256 ="HmacSHA256";
    public static final String ENCODE_UTF_8_LOWER ="utf-8";
    public static final String ENCODE_UTF_8_UPPER ="UTF-8";
    public static String MD5EncodeForHex(String secret, String message)
            throws Exception {
            String encodeStr;
        try{
            //HMAC_SHA256 加密
            Mac HMAC_SHA256 = Mac.getInstance(ENCODE_TYPE_HMAC_SHA_256);
            SecretKeySpec secre_spec = new SecretKeySpec(secret.getBytes(ENCODE_UTF_8_UPPER),ENCODE_TYPE_HMAC_SHA_256);
            HMAC_SHA256.init(secre_spec);
            byte[] bytes = HMAC_SHA256.doFinal(message.getBytes(ENCODE_UTF_8_UPPER));
            if (bytes==null || bytes.length<1){
                return null;
            }
            //字节转换为16进制字符串
            String SHA256 =byteToHex(bytes);
            //base64
            String BASE64 = Base64.getEncoder().encodeToString(SHA256.getBytes(ENCODE_UTF_8_UPPER));
            //url encode
            encodeStr = URLEncoder.encode(BASE64,ENCODE_UTF_8_LOWER);
        }catch (Exception e){
            throw new Exception("get 256 info error ....");
        }
        return encodeStr;
    }

    private static String byteToHex(byte[] bytes){

        if (bytes==null){
            return null;
        }
        StringBuffer stringBuffer = new StringBuffer();
        String temp=null;
        for (int i = 0; i <bytes.length ; i++) {
            temp = Integer.toHexString(bytes[i]&0xff);
            if (temp.length()==1){
                stringBuffer.append("0");
            }
            stringBuffer.append(temp);
        }
        return stringBuffer.toString();
    }

}

Filter.SignAutheFilter

package com.sina.demo.Filter;


import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;

import com.sina.demo.utils.IpUtil;
import com.sina.demo.utils.MDUtils;

/**
 * 功能描述: 过滤器鉴权
 *
 * @Param:
 * @Return:
 * @Author: 方留龙
 * @Date:
 */


@WebFilter(urlPatterns = { "/authen/test1", "/authen/test2", "/authen/test3"})
public class SignAutheFilter implements Filter {

    private static Logger logger = LoggerFactory.getLogger(SignAutheFilter.class);

    @Value("${permitted-ips}")
    private String[] permittedIps;

    @Value("${secret}")
    private String secret;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        try {
            String authorization = request.getHeader("Authorization");
            logger.info("getted Authorization is ---> " + authorization);
            String[] info = authorization.split(",");

            // 获取客户端ip
            String ip = IpUtil.getIpAddr(request);
            logger.info("getted ip is ---> " + ip);
            int cardidIndex = info[0].indexOf("=") + 2;
            String cardid = info[0].substring(cardidIndex, info[0].length() - 1);
            logger.info("cardid is ---> " + cardid);
            int timestampIndex = info[1].indexOf("=") + 2;
            String timestamp = info[1].substring(timestampIndex, info[1].length() - 1);
            int signatureIndex = info[2].indexOf("=") + 2;
            String signature = info[2].substring(signatureIndex, info[2].length() - 1);
            String tmptString = MDUtils.MD5EncodeForHex(secret, timestamp)
                    .toUpperCase();
            logger.info("getted ciphertext is ---> {}, correct ciphertext is ---> {}",
                    signature , tmptString);
            System.out.println(tmptString);
            System.out.println("++++++++");
            // 判断该ip是否合法
            boolean containIp = false;
            for (String string : permittedIps) {
                if (string.equals(ip)) {
                    containIp = true;
                    break;
                }
            }

            // 再判断Authorization内容是否正确,进而判断是否最终放行
            boolean couldPass = containIp && tmptString.equals(signature);
            if (couldPass) {
                // 放行
                chain.doFilter(request, response);
                return;
            }

            response.sendError(403, "Forbidden");
        } catch (Exception e) {
            logger.error("AxbAuthenticationFilter -> " + e.getMessage(), e);
            response.sendError(403, "Forbidden");
        }
    }

    @Override
    public void destroy() {
    }

}

controller.AuthenController

package com.sina.demo.controller;

import org.springframework.web.bind.annotation.*;

@RestController
public class AuthenController {

    @PostMapping("/authen/test1")
    public String test1(@RequestHeader("Authorization") String autho, @RequestBody String motto){
        return "进来了1!" + "\n" + autho + "\n" + motto;
    }
    @GetMapping("/authen/test2")
    public String test2(){
        return "进来了2!";
    }
    @PostMapping("/authen/test3")
    public String test3(){
        return "进来了3!";
    }
}

测试

注:cardid无意义,可以在后台删除省去,timestamp为时间戳,signature为前后台设定的secret和timestamp加密得到的,可以进行一次访问将其打印出来,在请求时带上即可。timestamp改变signature也会改变。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值