zoukankan      html  css  js  c++  java
  • Springboot 实现api校验和登录验证

    https://blog.csdn.net/qq_36085004/article/details/83348144 

    API校验

    场景

    在前后端分离开发时,后端获取数据就是通过异步请求调我们的API接口,但是,如果我们不做安全处理,其他人也可以直接调我们的API,这会让我们的数据泄露。因此,为了让我们的API只能被我们允许的人调用,我们对我们的API进行安全处理,他人在调用我们的API时需要进行校验,符合的才允许调用API。

    实现思路

    客户端:
    调用我们API的人需要用时间戳timestamp,随机字符串noncestr,请求参数以升序排列拼接成一个字符串,并使用MD5进行加密生成一个签名sign。
    在发送请求时,将timestamp, noncestr,sign发送给后台

    后台:
    编写一个拦截器,将所有的请求拦截。
    在拦截器中进行请求校验:
    1,请求参数sign是否为空,为空返回false。
    2,timestamp 加十分钟(超过10分钟请求过期)是否小于服务端当前时间戳,小于返回false。
    3,后台获取所有参数,以同样的规则拼接字符串,使用MD5加密,得到一个签名,用得到的签名和请求传来的签名进行比较,相同则放行,不同返回false。

    代码

    拦截器:
    package com.xyy.edlp.intercepter;
    
    import org.springframework.util.DigestUtils;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.*;
    
    /**
     * @Author: perkins
     */
    public class ApiSignatureInterceptor extends HandlerInterceptorAdapter {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                                 Object handler) throws Exception {
            Enumeration<String> paramNames = request.getParameterNames();
            String timestamp = request.getHeader("timestamp");
    
            long timestampDate = Long.valueOf(timestamp) + 1000*60*10;
            long currDate = System.currentTimeMillis();
            // 请求过期
            if (timestampDate < currDate) {
                response.setStatus(403);
                return false;
            }
    
            String noncestr = request.getHeader("noncestr");
            String signature = request.getParameter("sign");
            System.out.println(signature);
    
            if (signature == null) {
                response.setStatus(403);
                return false;
            }
            Map map = new HashMap();
    
            //获取所有的请求参数
            while (paramNames.hasMoreElements()) {
                String paramName = paramNames.nextElement();
                String[] paramValues = request.getParameterValues(paramName);
    
                if (paramValues.length > 0) {
                    String paramValue = paramValues[0];
                    System.out.println(paramName);
                    if (paramValue.length() != 0 && !"sign".equals(paramName)) {
                        map.put(paramName, paramValue);
                    }
                }
            }
    
            Set setKey = map.keySet();
            Object[] keys = setKey.toArray();
            // 将请求参数升序排序
            Arrays.sort(keys);
    
            StringBuilder strBuilder = new StringBuilder();
            for (Object str : keys) {
                strBuilder.append(str.toString());
                strBuilder.append(map.get(str.toString()));
            }
    
            strBuilder.append("noncestr");
            strBuilder.append(noncestr);
            strBuilder.append("timestamp");
            strBuilder.append(timestamp);
    
            System.out.println(strBuilder.toString());
            String newSignature = DigestUtils.md5DigestAsHex(strBuilder.toString().getBytes()).toUpperCase();
    
            if (!signature.equals(newSignature)) {
                response.setStatus(403);
                return false;
            }
            return true;
        }
    }
    
    
    拦截器注册:
    @Configuration
    public class WebConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry){
            registry.addInterceptor(new ApiSignatureInterceptor());
        }
    }
    

    登录token权限验证

    场景

    系统中,有的api必须用户登陆了才能够调用,因此,必须给这样的api进行安全防护。

    实现思路

    1,客户端调用登录接口,登录成功,使用JWT生成一个token,将token以UID—token键值对的形式存入redis,返回给客户端一个token和UID。
    2,创建一个拦截器,对需要登录权限的接口进行拦截,判断请求中是否有token,根据UID从redis中取出对应的token,对请求中的token进行验证,然后再使用JWT验证token,都没问题放行,否则返回false。

    代码

    jwt生成token代码
    package com.xyy.edlp.util;
    
    
    import com.auth0.jwt.JWT;
    import com.auth0.jwt.JWTVerifier;
    import com.auth0.jwt.algorithms.Algorithm;
    import com.auth0.jwt.exceptions.JWTDecodeException;
    import com.auth0.jwt.interfaces.DecodedJWT;
    
    import java.io.UnsupportedEncodingException;
    import java.util.Date;
    
    /**
     * @Author: perkins
     */
    public class JwtUtil {
        private static final String encodeSecretKey = "XX#$%()(#*!()!KL<><MQLMNQNQJQKsdfkjsdrow32234545fdf>?N<:{LWPW";
    
        /**
         * token过期时间
         */
        private static final long EXPIRE_TIME = 1000 * 60 * 60 * 24 * 7;
    
        /**
         * 生成token
         * @return
         */
        public static String createToken(String account) {
            try {
                Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
                Algorithm algorithm = Algorithm.HMAC256(account + encodeSecretKey);
                return JWT.create()
                        .withExpiresAt(date)
                        .withClaim("account", account)
                        .sign(algorithm);
            } catch (UnsupportedEncodingException e) {
                return null;
            }
        }
    
        /**
         * 校验token是否失效
         * @param token
         * @return
         */
        public static boolean checkToken(String token, String account) {
            try {
                Algorithm algorithm = Algorithm.HMAC256(account + encodeSecretKey);
                JWTVerifier verifier = JWT.require(algorithm)
                        .build();
                DecodedJWT jwt = verifier.verify(token);
                return true;
            } catch (UnsupportedEncodingException e) {
                return false;
            }
        }
    
        /**
         * 获取用户account
         * @param token
         * @return
         */
        public static String getAccount(String token){
            try {
                DecodedJWT jwt = JWT.decode(token);
                return jwt.getClaim("account").asString();
            } catch (JWTDecodeException e) {
                return null;
            }
        }
    
        }
    
    拦截器代码:
    public class JwtInterceptor extends HandlerInterceptorAdapter {
    
        @Autowired
        RedisUtil redisUtil;
    
        @Override
        public boolean preHandle(HttpServletRequest request,
                                 HttpServletResponse response,
                                 Object handler) throws Exception {
            String token = request.getHeader("Authorization");
            if (token == null) {
                response.setStatus(401);
                return false;
            }
    
            String account = JwtUtil.getAccount(token);
            String redisToken = redisUtil.get(RedisKey.TP_STORE_KEY + account);
            boolean isExpire = JwtUtil.checkToken(token, account);
    
            if (redisToken == null || redisToken != token || isExpire) {
                response.setStatus(401);
                return false;
            }
            return true;
        }
    }
    拦截器注册:
    @Configuration
    public class WebConfig implements WebMvcConfigurer {
    
       // 再拦截器中使用了RedisUtil bean类,但是拦截器执行实在spring容器bean初始化之前的
       // RedisUtil 将无法注入,为了解决该问题,将JwtInterceptor拦截器先配置为一个bean
       // 在注册拦截器时,直接使用配置的bean
        @Bean
        public JwtInterceptor jwtInterceptor(){
            return new JwtInterceptor();
        }
    
        @Override
        public void addInterceptors(InterceptorRegistry registry){
            registry.addInterceptor(jwtInterceptor())
                    .addPathPatterns("/tp_store/logout");
        }
    }
  • 相关阅读:
    人月神话阅读笔记03(完)
    人月神话阅读笔记02
    各种前端好用的在线工具、学习网站、插件
    垂直居中css
    输入框判断表情的输入js
    jq九宫格抽奖
    移动端中一像素的解决方案
    获取url地址栏中的参数数据
    ios中getTime()的兼容性问题
    清除Css中select的下拉箭头样式
  • 原文地址:https://www.cnblogs.com/yelanggu/p/10320725.html
Copyright © 2011-2022 走看看