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

posted @ 2020-01-29 17:13  caofanqi  阅读(723)  评论(0编辑  收藏  举报