zoukankan      html  css  js  c++  java
  • API安全(四)-认证

    1、什么是认证

      认证是指我们去验证用户身份是否合法的过程。

    2、认证和登陆的区别

      很多人会把认证和登陆混为一谈,其实两者完全是两个概念。认证不是登陆,登陆是指用户获取身份证明的一个过程,认证是指我们去验证这个用户身份是否合法的过程。

      登陆的行为,往往只发生一次,登陆成功后,会保存一段时间用户信息。而认证,每次请求去调用业务逻辑的时候都会去执行。

      再有就是登陆一旦有问题,就不会继续往下走,比如说,登陆时用户名或密码填写错误了,这时会进行报错或返回,不会继续往下执行。而认证的话,不管认证信息是否正确,在整个安全机制链路中还是会继续往下执行(如下图),让后面的审计机制,去记录这次身份认证的结果是什么样子的。最终请求是不是可以被通过,要由授权来决定。而不是由认证来决定的。比如说当前请求没有用户认证信息或者认证机制根本没生效,但是这个请求,有可能是可以正常访问的。比如说首页,获取商品信息等。

    3、HttpBasic认证

      基于http协议的认证方式由很多,这里,我们先了解一下最简单的HttpBasic认证,这是一个最基础的认证。HttpBasic验证方案是在 RFC 7617中规定的,在该方案中,使用用户的 ID/密码作为凭证信息,并且使用 base64 算法进行编码。

      步骤:3.1、用冒号将用户名和密码进行拼接(如:aladdin:opensesame)。

           3.2、将第一步生成的结果用 base64 方式编码(YWxhZGRpbjpvcGVuc2VzYW1l)。

           3.3、将编码后的字符串拼接上验证类型Basic 放入到请求头Authorization中(Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l)。

      注意:对于需要在浏览器进行弹出输入用户名和密码框的,要在相应头中添加WWW-Authenticate并且Http状态码为401。

      优点:简单,方便,所有的主流浏览器都支持。

      缺点:Base64编码并不是一种加密方法或者hashing方法!这种方法的安全性与明文发送等同(base64可以逆向解码)。“基本验证”方案需要与HTTPS协议配合使用。

     

      http身份认证参考文档:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Authentication

      请求头Authorization参考文档:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Authorization

    4、代码示例

       4.1、数据准备

      

      4.2、编写HttpBasic认证过滤器

    /**
     * HttpBasic 认证
     *
     * @author caofanqi
     * @date 2020/1/21 15:10
     */
    @Slf4j
    @Component
    @SuppressWarnings("ALL")
    public class BasicAuthorizationFilter extends OncePerRequestFilter {
    
        @Resource
        private UserRepository userRepository;
    
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    
            String authorizationHeader = request.getHeader("Authorization");
    
            if (StringUtils.isNotBlank(authorizationHeader)) {
    
                String token64 = StringUtils.substringAfter(authorizationHeader, "Basic ");
    
                if (StringUtils.isNotBlank(token64)) {
                    try {
                        String token = new String(Base64Utils.decodeFromString(token64));
                        String[] items = StringUtils.splitByWholeSeparatorPreserveAllTokens(token, ":");
                        String username = items[0];
                        String password = items[1];
    
                        UserDO user = userRepository.findByUsername(username);
    
                        if (user != null && StringUtils.equals(user.getPassword(), password)) {
                            //认证通过,存放用户信息
                            request.setAttribute("user", user);
                        }
    
                    } catch (Exception e) {
                        log.info("Basic Authorization Fail!");
                    }
                }
    
            }
    
            //不管认证是否正确,继续往下走,是否可以访问,交给授权处理
            filterChain.doFilter(request, response);
    
        }
    
    }

      4.3、因为我们还没有学习授权机制,所以这里使用代码来控制,UserController获取用户信息方法

        @GetMapping("/{id}")
        public UserDTO get(@PathVariable Long id, HttpServletRequest request, HttpServletResponse response) throws IOException {
    
            /*
             * 因为还没有学习授权机制,这里写代码进行控制
             */
            UserDO user = (UserDO) request.getAttribute("user");
    
            if (user == null){
                //说明没有进行认证,返回401和WWW-Authenticate
                response.setStatus(HttpStatus.UNAUTHORIZED.value());
                response.setHeader("WWW-Authenticate","Basic realm=<authentication required>");
                return null;
            }
    
            if (!user.getId().equals(id)){
                //只能查看自己的用户信息,不是本人,返回403
                response.setStatus(HttpStatus.FORBIDDEN.value());
                response.getWriter().write("permission denied");
                response.getWriter().flush();
                return null;
            }
    
            return userService.get(id);
        }

      4.4、启动项目,访问http://127.0.0.1:9090/users/1,会弹出输入框,我们输入lisi的用户名和密码

      

      这时我们查看请求头中已经带有Authorization认证信息,但是还是返回给我们403,那是因为lisi的id为2。

      

      访问http://127.0.0.1:9090/users/2 ,可以正常获取用户信息

      

    项目源码: https://github.com/caofanqi/study-security/tree/dev-httpbasic

  • 相关阅读:
    HDU 3068 Manacher
    HDU 6188最小费用流
    Codeforces Round #442 (Div. 2) Danil and a Part-time Job
    并查集
    HDU 5988最小网络流(浮点数)
    HOJ
    HOJ
    POJ
    POJ
    关于async
  • 原文地址:https://www.cnblogs.com/caofanqi/p/12222410.html
Copyright © 2011-2022 走看看