zoukankan      html  css  js  c++  java
  • Spring cloud微服务安全实战-3-5 API安全机制之认证(2)

    基于Http协议的认证方式有很多。本节我们只讲一个最简单的HttpBasic认证。聪明就可以看出来,这是一个最基础的认证,好处是简单方便,所有的主流浏览器都支持,问题就是并不是非常安全的,但是帮我们大家理解认证这个概念是足够的。

    首先要对认证信息做Base64的加密,加密之前要把这两个信息组合起来。用户名冒号密码组合成这样一个字符串。然后拿这个字符串做Base64的字符串的加密。并生成一个字符串。

    把生成的串放到http请求的 请求头里面。带个前缀 Basic +空格 + 加密后的字符串。

    开始写代码


    先加上字符串处理的工具的引用。commons-lang3这里面有个字符串处理的工具类

    <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    </dependency>


    建一个新的过滤器BaseicAuthecationFilter

    继承OncePerRequestFilter


    @Component声明称一个组件,这样SpringBoot会自动把他加到应用的过滤器链上。

    注入UserRepository



    用java.util这个包下的也可以,用Base64Utils这个也可以。

    根据冒号拆分成两个字符串

    创建这个根据UserName查询的方法



    之前写的findByName删掉。

    User findByUsername(String username);


    StringUtils用的都是apache.commons.lang3这个包下的类。

    package com.imooc.security.filter;
    
    import com.imooc.security.user.User;
    import com.imooc.security.user.UserRepository;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.util.Base64Utils;
    import org.springframework.web.filter.OncePerRequestFilter;
    
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    @Component
    public class BasicAuthecationFilter extends OncePerRequestFilter {
    
        @Autowired
        private UserRepository userRepository;
    
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            String authHeader = request.getHeader("Authorization");
            if(StringUtils.isNotBlank(authHeader)){
                String token64 = StringUtils.substringAfter(authHeader, "Basic ");
                String token = new String(Base64Utils.decodeFromString(token64));//解码
                //根据冒号拆分成两个字符串
                String[] items = StringUtils.splitByWholeSeparatorPreserveAllTokens(token, ":");
                String username = items[0];
                String password = items[1];
                User user = userRepository.findByUsername(username);
                if(user!=null && StringUtils.equals(password,user.getPassword())){
                    request.setAttribute("user",user);
                }
            }
            filterChain.doFilter(request,response);
        }
    }
    Filter代码



    因为我们还没有写审计等的代码,这里我们先在controller里面写代码,先看到效果。
    user里面getId获取到id和当前的接口传递过来的参数id对象,如果不相等就抛出异常。

    遇到的错误

    出现问题的原因

    修改成Long即可

    继续


    在User实体类里面。写一个方法,buildInfo,。把User对象转换成UserInfo对象。

    
    
    public UserInfo buildInfo(){
    UserInfo info=new UserInfo();
    BeanUtils.copyProperties(this,info);
    return info;
    }
     


    JPA提供的findById默认的返回类型是一个Optional的类型。

    UserServiceImpl 。所以要先get()再调用buildInfo()

     public UserInfo get(Long id) {
            return userRepository.findById(id).get().buildInfo();
        }

    运行测试

    现在在请求头里面根本没有带认证信息。这里是个get请求。查询id为1的用户信息

    {
        "timestamp": "2019-12-10T09:05:46.377+0000",
        "status": 500,
        "error": "Internal Server Error",
        "message": "身份认证信息异常,获取用户信息失败",
        "path": "/users/1"
    }


    在过滤器里面,相当于这一段完全没有执行

    经过过滤器会进入到controller里面。在Arttribute里面拿到的是空。所以就抛出了异常。

       @GetMapping("/{id}")
        public UserInfo get(@PathVariable Long id, HttpServletRequest request){
            User user=(User) request.getAttribute("user");
    
    
            if(user == null || !user.getId().equals(id)) {
                throw new RuntimeException("身份认证信息异常,获取用户信息失败");
            }
            return userService.get(id);
        }







    发出去的完整的信息里面已经带了请求头的信息了。但是 依然报了异常

    这是因为创建的用户的id是5 但是回去的用户信息id是1。所以造成了id的不匹配。

    把请求的id改成5


    这样用户信息成功返回

    以上就是认证起作用的一个简单的例子。
     

    postman里面的设置

     

    结束

     

  • 相关阅读:
    python库安装
    Reversing Linked List(根据输入序列对其做部分或全部反转)
    简单的一元二项(使用的是指针形式,方便调试)
    最大子序列问题
    centos6安装mysql5.5.53
    android中常用的drawable
    android四大组件之ContentProvider
    android使用shape来绘制控件
    android布局理解
    android命令行管理avd以及sqlite3命令
  • 原文地址:https://www.cnblogs.com/wangjunwei/p/11903806.html
Copyright © 2011-2022 走看看