API安全(九)-授权
2021-01-15 08:13
标签:name file doc The local 无权限 his inter authorize 授权在整个安全机制中,是比较重要的一环,一般要考虑两个事情,一个是访问的请求需不需要身份认证,如果不需要直接放过,如果需要,但是没有认证,应该返回401,需要用户进行认证。另一个就是,认证了,看有没有该资源的访问权限,如果有,放行;如果没有返回403,无权限。 2.1、ACL :Access Control Lists,简单易用,容易实现。常见读写等少量权限控制。 2.2、RBAC:Role Based Access Control。引入角色,方便管理权限。开发交ACL复杂。 这里我们实现一个简单的ACL权限控制,要求,所有的请求都必须经过认证,可以为用户授予读写权限,读权限可以访问GET请求,其他请求需要有写权限。 3.1、在用户实体中添加权限字段 3.2、使用Filter进行授权控制(这要求审计也是基于Filter实现的,保证各安全模块的执行顺序) 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、如果审计模块使用的是拦截器实现,授权也要使用拦截器,效果一样 项目源码:https://github.com/caofanqi/study-security/tree/dev-authorization API安全(九)-授权 标签:name file doc The local 无权限 his inter authorize 原文地址:https://www.cnblogs.com/caofanqi/p/12240794.html
1、授权
2、常见的访问控制
3、使用ACL实现授权控制
/**
* @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;
}
}
/**
* 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=");
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");
}
}
}
/**
* 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=");
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);
}
}