zoukankan      html  css  js  c++  java
  • API安全(九)-授权

    1、授权

      授权在整个安全机制中,是比较重要的一环,一般要考虑两个事情,一个是访问的请求需不需要身份认证,如果不需要直接放过,如果需要,但是没有认证,应该返回401,需要用户进行认证。另一个就是,认证了,看有没有该资源的访问权限,如果有,放行;如果没有返回403,无权限。

    2、常见的访问控制

      2.1、ACL :Access Control Lists,简单易用,容易实现。常见读写等少量权限控制。

      2.2、RBAC:Role Based Access Control。引入角色,方便管理权限。开发交ACL复杂。

    3、使用ACL实现授权控制

      这里我们实现一个简单的ACL权限控制,要求,所有的请求都必须经过认证,可以为用户授予读写权限,读权限可以访问GET请求,其他请求需要有写权限。

      3.1、在用户实体中添加权限字段

    /**
     * @author caofanqi
     * @date 2020/1/20 13:08
     */
    @Data
    @Entity
    @Table(name = "user")
    public class UserDO {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column(nullable = false)
        private String name;
    
        @Column(nullable = false,unique = true)
        private String username;
    
        @Column(nullable = false)
        private String password;
    
        /**
         *  用户具有的权限信息,多个用逗号隔开;read读权限,write写权限
         */
        private String permissions;
    
    
        public UserDTO buildUserDTO(){
            UserDTO userDTO = new UserDTO();
            BeanUtils.copyProperties(this,userDTO);
            return userDTO;
        }
    
    }

      3.2、使用Filter进行授权控制(这要求审计也是基于Filter实现的,保证各安全模块的执行顺序)

    /**
     * ACL过滤器
     *
     * @author caofanqi
     * @date 2020/1/29 15:04
     */
    @Slf4j
    @Order(4)
    @Component
    public class AclFilter extends OncePerRequestFilter {
    
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            log.info("++++++4、授权++++++");
    
            /*
             * 要求请求都必须经过认证才能访问
             */
            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;
            }
    
            /*
             * 要求有对应的权限才可以进行访问
             */
            if (!hasPermission(user.getPermissions(), request.getMethod())) {
                response.setStatus(HttpStatus.FORBIDDEN.value());
                response.getWriter().write("Forbidden");
                response.getWriter().flush();
                return;
            }
    
    
            filterChain.doFilter(request, response);
    
        }
    
        private boolean hasPermission(String permissions, String method) {
    
            if (StringUtils.equalsIgnoreCase(method, HttpMethod.GET.name())) {
                //要有读权限
                return StringUtils.containsIgnoreCase(permissions, "read");
            } else {
                //要有写权限
                return StringUtils.containsIgnoreCase(permissions, "write");
            }
    
        }
    
    }

      3.3、启动项目,在数据库中为用户赋予相应权限如下

      3.4、使用创建用户进行测试 http://127.0.0.1:9090/users

        3.4.1、使用未认证的进行访问,弹出认证框

       控制台过滤器执行顺序如下

       数据库日志如下

        3.4.2、使用带有读权限的tom进行认证,创建用户失败,返回403无权限

        3.4.3、使用带有读写权限的jack进行认证,创建用户成功

      3.3、如果审计模块使用的是拦截器实现,授权也要使用拦截器,效果一样

    /**
     * ACL拦截器
     *
     * @author caofanqi
     * @date 2020/1/29 15:31
     */
    @Slf4j
    //@Component
    public class AclInterceptor extends HandlerInterceptorAdapter {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
    
            log.info("++++++4、授权++++++");
    
            UserDO user = (UserDO) request.getAttribute("user");
            if (user == null) {
                response.setStatus(HttpStatus.UNAUTHORIZED.value());
                response.setHeader("WWW-Authenticate", "Basic realm=<authentication required>");
                return false;
            }
    
            if (!hasPermission(user.getPermissions(), request.getMethod())) {
                response.setStatus(HttpStatus.FORBIDDEN.value());
                response.getWriter().write("Forbidden");
                response.getWriter().flush();
                return false;
            }
    
            return true;
        }
    
        private boolean hasPermission(String permissions, String method) {
    
            if (StringUtils.equalsIgnoreCase(method, HttpMethod.GET.name())) {
                return StringUtils.containsIgnoreCase(permissions, "read");
            } else {
                return StringUtils.containsIgnoreCase(permissions, "write");
            }
        }
    
    }
    /**
     * web配置类
     *
     * @author caofanqi
     * @date 2020/1/28 22:32
     */
    @Configuration
    public class WebConfig implements WebMvcConfigurer {
    
    
        @Resource
        private AuditLogInterceptor auditLogInterceptor;
    
        @Resource
        private AclInterceptor aclInterceptor;
    
        /**
         * 注册拦截器,拦截器的执行顺序取决于add顺序
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(auditLogInterceptor);
            registry.addInterceptor(aclInterceptor);
        }
    
    }

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

  • 相关阅读:
    TabControl
    Loading
    Dialog
    Combobox
    Markdown编辑器Editor.md使用方式
    XSS攻击
    跨域解决方案及实现
    angular4 自定义表单组件
    angular4 Form表单相关
    js 详解setTimeout定时器
  • 原文地址:https://www.cnblogs.com/caofanqi/p/12240794.html
Copyright © 2011-2022 走看看