dashboard: Add interface of authentication/authorization and provide a default stub implementation (#503)

Signed-off-by: Carpenter Lee <hooleeucas@163.com>
This commit is contained in:
Carpenter Lee 2019-03-14 10:03:03 +08:00 committed by Eric Zhao
parent 4b1ccd93e2
commit 3c52bbc3c8
9 changed files with 375 additions and 30 deletions

View File

@ -15,12 +15,24 @@
*/ */
package com.alibaba.csp.sentinel.dashboard.config; package com.alibaba.csp.sentinel.dashboard.config;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Filter; import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter; import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import com.alibaba.csp.sentinel.dashboard.service.AuthService;
import com.alibaba.csp.sentinel.dashboard.service.AuthService.AuthUser;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -35,6 +47,8 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
public class WebConfig implements WebMvcConfigurer { public class WebConfig implements WebMvcConfigurer {
private final Logger logger = LoggerFactory.getLogger(WebConfig.class); private final Logger logger = LoggerFactory.getLogger(WebConfig.class);
@Autowired
private AuthService<HttpServletRequest> authService;
@Override @Override
public void addResourceHandlers(ResourceHandlerRegistry registry) { public void addResourceHandlers(ResourceHandlerRegistry registry) {
@ -62,4 +76,36 @@ public class WebConfig implements WebMvcConfigurer {
return registration; return registration;
} }
@Bean
public FilterRegistrationBean authenticationFilterRegistration() {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
registration.setFilter(new Filter() {
@Override
public void init(FilterConfig filterConfig) throws ServletException { }
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
AuthUser authUser = authService.getAuthUser(request);
// authentication fail
if (authUser == null) {
PrintWriter writer = servletResponse.getWriter();
writer.append("login needed");
writer.flush();
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
@Override
public void destroy() { }
});
registration.addUrlPatterns("/*");
registration.setName("authenticationFilter");
registration.setOrder(0);
return registration;
}
} }

View File

@ -18,14 +18,20 @@ package com.alibaba.csp.sentinel.dashboard.controller;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletRequest;
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient; import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo; import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
import com.alibaba.csp.sentinel.dashboard.service.AuthService;
import com.alibaba.csp.sentinel.dashboard.service.AuthService.AuthUser;
import com.alibaba.csp.sentinel.dashboard.service.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity; import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
import com.alibaba.csp.sentinel.dashboard.domain.Result; import com.alibaba.csp.sentinel.dashboard.domain.Result;
import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository; import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -54,10 +60,16 @@ public class AuthorityRuleController {
@Autowired @Autowired
private RuleRepository<AuthorityRuleEntity, Long> repository; private RuleRepository<AuthorityRuleEntity, Long> repository;
@Autowired
private AuthService<HttpServletRequest> authService;
@GetMapping("/rules") @GetMapping("/rules")
public Result<List<AuthorityRuleEntity>> apiQueryAllRulesForMachine(@RequestParam String app, public Result<List<AuthorityRuleEntity>> apiQueryAllRulesForMachine(HttpServletRequest request,
@RequestParam String app,
@RequestParam String ip, @RequestParam String ip,
@RequestParam Integer port) { @RequestParam Integer port) {
AuthUser authUser = authService.getAuthUser(request);
authUser.authTarget(app, PrivilegeType.READ_RULE);
if (StringUtil.isEmpty(app)) { if (StringUtil.isEmpty(app)) {
return Result.ofFail(-1, "app cannot be null or empty"); return Result.ofFail(-1, "app cannot be null or empty");
} }
@ -107,7 +119,10 @@ public class AuthorityRuleController {
} }
@PostMapping("/rule") @PostMapping("/rule")
public Result<AuthorityRuleEntity> apiAddAuthorityRule(@RequestBody AuthorityRuleEntity entity) { public Result<AuthorityRuleEntity> apiAddAuthorityRule(HttpServletRequest request,
@RequestBody AuthorityRuleEntity entity) {
AuthUser authUser = authService.getAuthUser(request);
authUser.authTarget(entity.getApp(), PrivilegeType.WRITE_RULE);
Result<AuthorityRuleEntity> checkResult = checkEntityInternal(entity); Result<AuthorityRuleEntity> checkResult = checkEntityInternal(entity);
if (checkResult != null) { if (checkResult != null) {
return checkResult; return checkResult;
@ -129,8 +144,11 @@ public class AuthorityRuleController {
} }
@PutMapping("/rule/{id}") @PutMapping("/rule/{id}")
public Result<AuthorityRuleEntity> apiUpdateParamFlowRule(@PathVariable("id") Long id, public Result<AuthorityRuleEntity> apiUpdateParamFlowRule(HttpServletRequest request,
@PathVariable("id") Long id,
@RequestBody AuthorityRuleEntity entity) { @RequestBody AuthorityRuleEntity entity) {
AuthUser authUser = authService.getAuthUser(request);
authUser.authTarget(entity.getApp(), PrivilegeType.WRITE_RULE);
if (id == null || id <= 0) { if (id == null || id <= 0) {
return Result.ofFail(-1, "Invalid id"); return Result.ofFail(-1, "Invalid id");
} }
@ -158,7 +176,8 @@ public class AuthorityRuleController {
} }
@DeleteMapping("/rule/{id}") @DeleteMapping("/rule/{id}")
public Result<Long> apiDeleteRule(@PathVariable("id") Long id) { public Result<Long> apiDeleteRule(HttpServletRequest request, @PathVariable("id") Long id) {
AuthUser authUser = authService.getAuthUser(request);
if (id == null) { if (id == null) {
return Result.ofFail(-1, "id cannot be null"); return Result.ofFail(-1, "id cannot be null");
} }
@ -166,6 +185,7 @@ public class AuthorityRuleController {
if (oldEntity == null) { if (oldEntity == null) {
return Result.ofSuccess(null); return Result.ofSuccess(null);
} }
authUser.authTarget(oldEntity.getApp(), PrivilegeType.DELETE_RULE);
try { try {
repository.delete(id); repository.delete(id);
} catch (Exception e) { } catch (Exception e) {

View File

@ -18,14 +18,20 @@ package com.alibaba.csp.sentinel.dashboard.controller;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletRequest;
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient; import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo; import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
import com.alibaba.csp.sentinel.dashboard.service.AuthService;
import com.alibaba.csp.sentinel.dashboard.service.AuthService.AuthUser;
import com.alibaba.csp.sentinel.dashboard.service.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity; import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
import com.alibaba.csp.sentinel.dashboard.domain.Result; import com.alibaba.csp.sentinel.dashboard.domain.Result;
import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemDegradeRuleStore; import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemDegradeRuleStore;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -48,9 +54,15 @@ public class DegradeController {
@Autowired @Autowired
private SentinelApiClient sentinelApiClient; private SentinelApiClient sentinelApiClient;
@Autowired
private AuthService<HttpServletRequest> authService;
@ResponseBody @ResponseBody
@RequestMapping("/rules.json") @RequestMapping("/rules.json")
public Result<List<DegradeRuleEntity>> queryMachineRules(String app, String ip, Integer port) { public Result<List<DegradeRuleEntity>> queryMachineRules(HttpServletRequest request, String app, String ip, Integer port) {
AuthUser authUser = authService.getAuthUser(request);
authUser.authTarget(app, PrivilegeType.READ_RULE);
if (StringUtil.isEmpty(app)) { if (StringUtil.isEmpty(app)) {
return Result.ofFail(-1, "app can't be null or empty"); return Result.ofFail(-1, "app can't be null or empty");
} }
@ -72,8 +84,12 @@ public class DegradeController {
@ResponseBody @ResponseBody
@RequestMapping("/new.json") @RequestMapping("/new.json")
public Result<DegradeRuleEntity> add(String app, String ip, Integer port, String limitApp, String resource, public Result<DegradeRuleEntity> add(HttpServletRequest request,
String app, String ip, Integer port, String limitApp, String resource,
Double count, Integer timeWindow, Integer grade) { Double count, Integer timeWindow, Integer grade) {
AuthUser authUser = authService.getAuthUser(request);
authUser.authTarget(app, PrivilegeType.WRITE_RULE);
if (StringUtil.isBlank(app)) { if (StringUtil.isBlank(app)) {
return Result.ofFail(-1, "app can't be null or empty"); return Result.ofFail(-1, "app can't be null or empty");
} }
@ -127,8 +143,10 @@ public class DegradeController {
@ResponseBody @ResponseBody
@RequestMapping("/save.json") @RequestMapping("/save.json")
public Result<DegradeRuleEntity> updateIfNotNull(Long id, String app, String limitApp, String resource, public Result<DegradeRuleEntity> updateIfNotNull(HttpServletRequest request,
Long id, String app, String limitApp, String resource,
Double count, Integer timeWindow, Integer grade) { Double count, Integer timeWindow, Integer grade) {
AuthUser authUser = authService.getAuthUser(request);
if (id == null) { if (id == null) {
return Result.ofFail(-1, "id can't be null"); return Result.ofFail(-1, "id can't be null");
} }
@ -141,6 +159,7 @@ public class DegradeController {
if (entity == null) { if (entity == null) {
return Result.ofFail(-1, "id " + id + " dose not exist"); return Result.ofFail(-1, "id " + id + " dose not exist");
} }
authUser.authTarget(entity.getApp(), PrivilegeType.WRITE_RULE);
if (StringUtil.isNotBlank(app)) { if (StringUtil.isNotBlank(app)) {
entity.setApp(app.trim()); entity.setApp(app.trim());
} }
@ -176,7 +195,8 @@ public class DegradeController {
@ResponseBody @ResponseBody
@RequestMapping("/delete.json") @RequestMapping("/delete.json")
public Result<Long> delete(Long id) { public Result<Long> delete(HttpServletRequest request, Long id) {
AuthUser authUser = authService.getAuthUser(request);
if (id == null) { if (id == null) {
return Result.ofFail(-1, "id can't be null"); return Result.ofFail(-1, "id can't be null");
} }
@ -185,6 +205,7 @@ public class DegradeController {
if (oldEntity == null) { if (oldEntity == null) {
return Result.ofSuccess(null); return Result.ofSuccess(null);
} }
authUser.authTarget(oldEntity.getApp(), PrivilegeType.DELETE_RULE);
try { try {
repository.delete(id); repository.delete(id);
} catch (Throwable throwable) { } catch (Throwable throwable) {

View File

@ -18,6 +18,11 @@ package com.alibaba.csp.sentinel.dashboard.controller;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletRequest;
import com.alibaba.csp.sentinel.dashboard.service.AuthService;
import com.alibaba.csp.sentinel.dashboard.service.AuthService.AuthUser;
import com.alibaba.csp.sentinel.dashboard.service.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient; import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
@ -25,6 +30,7 @@ import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo; import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
import com.alibaba.csp.sentinel.dashboard.domain.Result; import com.alibaba.csp.sentinel.dashboard.domain.Result;
import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemoryRuleRepositoryAdapter; import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemoryRuleRepositoryAdapter;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -51,14 +57,20 @@ public class FlowControllerV1 {
@Autowired @Autowired
private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository; private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;
@Autowired
private AuthService<HttpServletRequest> authService;
@Autowired @Autowired
private SentinelApiClient sentinelApiClient; private SentinelApiClient sentinelApiClient;
@GetMapping("/rules") @GetMapping("/rules")
public Result<List<FlowRuleEntity>> apiQueryMachineRules(@RequestParam String app, public Result<List<FlowRuleEntity>> apiQueryMachineRules(HttpServletRequest request,
@RequestParam String app,
@RequestParam String ip, @RequestParam String ip,
@RequestParam Integer port) { @RequestParam Integer port) {
AuthUser authUser = authService.getAuthUser(request);
authUser.authTarget(app, PrivilegeType.READ_RULE);
if (StringUtil.isEmpty(app)) { if (StringUtil.isEmpty(app)) {
return Result.ofFail(-1, "app can't be null or empty"); return Result.ofFail(-1, "app can't be null or empty");
} }
@ -126,7 +138,10 @@ public class FlowControllerV1 {
} }
@PostMapping("/rule") @PostMapping("/rule")
public Result<FlowRuleEntity> apiAddFlowRule(@RequestBody FlowRuleEntity entity) { public Result<FlowRuleEntity> apiAddFlowRule(HttpServletRequest request, @RequestBody FlowRuleEntity entity) {
AuthUser authUser = authService.getAuthUser(request);
authUser.authTarget(entity.getApp(), PrivilegeType.WRITE_RULE);
Result<FlowRuleEntity> checkResult = checkEntityInternal(entity); Result<FlowRuleEntity> checkResult = checkEntityInternal(entity);
if (checkResult != null) { if (checkResult != null) {
return checkResult; return checkResult;
@ -150,10 +165,14 @@ public class FlowControllerV1 {
} }
@PutMapping("/save.json") @PutMapping("/save.json")
public Result<FlowRuleEntity> updateIfNotNull(Long id, String app, public Result<FlowRuleEntity> updateIfNotNull(HttpServletRequest request, Long id, String app,
String limitApp, String resource, Integer grade, String limitApp, String resource, Integer grade,
Double count, Integer strategy, String refResource, Double count, Integer strategy, String refResource,
Integer controlBehavior, Integer warmUpPeriodSec, Integer maxQueueingTimeMs) { Integer controlBehavior, Integer warmUpPeriodSec,
Integer maxQueueingTimeMs) {
AuthUser authUser = authService.getAuthUser(request);
authUser.authTarget(app, PrivilegeType.WRITE_RULE);
if (id == null) { if (id == null) {
return Result.ofFail(-1, "id can't be null"); return Result.ofFail(-1, "id can't be null");
} }
@ -227,7 +246,8 @@ public class FlowControllerV1 {
} }
@DeleteMapping("/delete.json") @DeleteMapping("/delete.json")
public Result<Long> delete(Long id) { public Result<Long> delete(HttpServletRequest request, Long id) {
AuthUser authUser = authService.getAuthUser(request);
if (id == null) { if (id == null) {
return Result.ofFail(-1, "id can't be null"); return Result.ofFail(-1, "id can't be null");
} }
@ -235,6 +255,7 @@ public class FlowControllerV1 {
if (oldEntity == null) { if (oldEntity == null) {
return Result.ofSuccess(null); return Result.ofSuccess(null);
} }
authUser.authTarget(oldEntity.getApp(), PrivilegeType.DELETE_RULE);
try { try {
repository.delete(id); repository.delete(id);
} catch (Exception e) { } catch (Exception e) {

View File

@ -21,10 +21,15 @@ import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import javax.servlet.http.HttpServletRequest;
import com.alibaba.csp.sentinel.dashboard.client.CommandNotFoundException; import com.alibaba.csp.sentinel.dashboard.client.CommandNotFoundException;
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient; import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement; import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo; import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
import com.alibaba.csp.sentinel.dashboard.service.AuthService;
import com.alibaba.csp.sentinel.dashboard.service.AuthService.AuthUser;
import com.alibaba.csp.sentinel.dashboard.service.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.util.StringUtil;
@ -33,6 +38,7 @@ import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.ParamFlowRuleEn
import com.alibaba.csp.sentinel.dashboard.domain.Result; import com.alibaba.csp.sentinel.dashboard.domain.Result;
import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository; import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository;
import com.alibaba.csp.sentinel.dashboard.util.VersionUtils; import com.alibaba.csp.sentinel.dashboard.util.VersionUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -63,6 +69,9 @@ public class ParamFlowRuleController {
@Autowired @Autowired
private RuleRepository<ParamFlowRuleEntity, Long> repository; private RuleRepository<ParamFlowRuleEntity, Long> repository;
@Autowired
private AuthService<HttpServletRequest> authService;
private boolean checkIfSupported(String app, String ip, int port) { private boolean checkIfSupported(String app, String ip, int port) {
try { try {
return Optional.ofNullable(appManagement.getDetailApp(app)) return Optional.ofNullable(appManagement.getDetailApp(app))
@ -77,9 +86,12 @@ public class ParamFlowRuleController {
} }
@GetMapping("/rules") @GetMapping("/rules")
public Result<List<ParamFlowRuleEntity>> apiQueryAllRulesForMachine(@RequestParam String app, public Result<List<ParamFlowRuleEntity>> apiQueryAllRulesForMachine(HttpServletRequest request,
@RequestParam String app,
@RequestParam String ip, @RequestParam String ip,
@RequestParam Integer port) { @RequestParam Integer port) {
AuthUser authUser = authService.getAuthUser(request);
authUser.authTarget(app, PrivilegeType.READ_RULE);
if (StringUtil.isEmpty(app)) { if (StringUtil.isEmpty(app)) {
return Result.ofFail(-1, "app cannot be null or empty"); return Result.ofFail(-1, "app cannot be null or empty");
} }
@ -115,7 +127,10 @@ public class ParamFlowRuleController {
} }
@PostMapping("/rule") @PostMapping("/rule")
public Result<ParamFlowRuleEntity> apiAddParamFlowRule(@RequestBody ParamFlowRuleEntity entity) { public Result<ParamFlowRuleEntity> apiAddParamFlowRule(HttpServletRequest request,
@RequestBody ParamFlowRuleEntity entity) {
AuthUser authUser = authService.getAuthUser(request);
authUser.authTarget(entity.getApp(), PrivilegeType.WRITE_RULE);
Result<ParamFlowRuleEntity> checkResult = checkEntityInternal(entity); Result<ParamFlowRuleEntity> checkResult = checkEntityInternal(entity);
if (checkResult != null) { if (checkResult != null) {
return checkResult; return checkResult;
@ -177,7 +192,10 @@ public class ParamFlowRuleController {
} }
@PutMapping("/rule/{id}") @PutMapping("/rule/{id}")
public Result<ParamFlowRuleEntity> apiUpdateParamFlowRule(@PathVariable("id") Long id, @RequestBody ParamFlowRuleEntity entity) { public Result<ParamFlowRuleEntity> apiUpdateParamFlowRule(HttpServletRequest request,
@PathVariable("id") Long id,
@RequestBody ParamFlowRuleEntity entity) {
AuthUser authUser = authService.getAuthUser(request);
if (id == null || id <= 0) { if (id == null || id <= 0) {
return Result.ofFail(-1, "Invalid id"); return Result.ofFail(-1, "Invalid id");
} }
@ -185,6 +203,7 @@ public class ParamFlowRuleController {
if (oldEntity == null) { if (oldEntity == null) {
return Result.ofFail(-1, "id " + id + " does not exist"); return Result.ofFail(-1, "id " + id + " does not exist");
} }
authUser.authTarget(oldEntity.getApp(), PrivilegeType.WRITE_RULE);
Result<ParamFlowRuleEntity> checkResult = checkEntityInternal(entity); Result<ParamFlowRuleEntity> checkResult = checkEntityInternal(entity);
if (checkResult != null) { if (checkResult != null) {
return checkResult; return checkResult;
@ -214,7 +233,8 @@ public class ParamFlowRuleController {
} }
@DeleteMapping("/rule/{id}") @DeleteMapping("/rule/{id}")
public Result<Long> apiDeleteRule(@PathVariable("id") Long id) { public Result<Long> apiDeleteRule(HttpServletRequest request, @PathVariable("id") Long id) {
AuthUser authUser = authService.getAuthUser(request);
if (id == null) { if (id == null) {
return Result.ofFail(-1, "id cannot be null"); return Result.ofFail(-1, "id cannot be null");
} }
@ -222,6 +242,7 @@ public class ParamFlowRuleController {
if (oldEntity == null) { if (oldEntity == null) {
return Result.ofSuccess(null); return Result.ofSuccess(null);
} }
authUser.authTarget(oldEntity.getApp(), PrivilegeType.DELETE_RULE);
try { try {
repository.delete(id); repository.delete(id);
publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort()).get(); publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort()).get();
@ -245,7 +266,8 @@ public class ParamFlowRuleController {
} }
private <R> Result<R> unsupportedVersion() { private <R> Result<R> unsupportedVersion() {
return Result.ofFail(4041, "Sentinel client not supported for parameter flow control (unsupported version or dependency absent)"); return Result.ofFail(4041,
"Sentinel client not supported for parameter flow control (unsupported version or dependency absent)");
} }
private final SentinelVersion version020 = new SentinelVersion().setMinorVersion(2); private final SentinelVersion version020 = new SentinelVersion().setMinorVersion(2);

View File

@ -18,6 +18,11 @@ package com.alibaba.csp.sentinel.dashboard.controller;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletRequest;
import com.alibaba.csp.sentinel.dashboard.service.AuthService;
import com.alibaba.csp.sentinel.dashboard.service.AuthService.AuthUser;
import com.alibaba.csp.sentinel.dashboard.service.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.SystemRuleEntity; import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.SystemRuleEntity;
@ -25,6 +30,7 @@ import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient; import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
import com.alibaba.csp.sentinel.dashboard.domain.Result; import com.alibaba.csp.sentinel.dashboard.domain.Result;
import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemSystemRuleStore; import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemSystemRuleStore;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -45,10 +51,14 @@ public class SystemController {
private InMemSystemRuleStore repository; private InMemSystemRuleStore repository;
@Autowired @Autowired
private SentinelApiClient sentinelApiClient; private SentinelApiClient sentinelApiClient;
@Autowired
private AuthService<HttpServletRequest> authService;
@ResponseBody @ResponseBody
@RequestMapping("/rules.json") @RequestMapping("/rules.json")
Result<List<SystemRuleEntity>> queryMachineRules(String app, String ip, Integer port) { Result<List<SystemRuleEntity>> queryMachineRules(HttpServletRequest request, String app, String ip, Integer port) {
AuthUser authUser = authService.getAuthUser(request);
authUser.authTarget(app, PrivilegeType.READ_RULE);
if (StringUtil.isEmpty(app)) { if (StringUtil.isEmpty(app)) {
return Result.ofFail(-1, "app can't be null or empty"); return Result.ofFail(-1, "app can't be null or empty");
} }
@ -80,7 +90,10 @@ public class SystemController {
@ResponseBody @ResponseBody
@RequestMapping("/new.json") @RequestMapping("/new.json")
Result<?> add(String app, String ip, Integer port, Double avgLoad, Long avgRt, Long maxThread, Double qps) { Result<?> add(HttpServletRequest request,
String app, String ip, Integer port, Double avgLoad, Long avgRt, Long maxThread, Double qps) {
AuthUser authUser = authService.getAuthUser(request);
authUser.authTarget(app, PrivilegeType.WRITE_RULE);
if (StringUtil.isBlank(app)) { if (StringUtil.isBlank(app)) {
return Result.ofFail(-1, "app can't be null or empty"); return Result.ofFail(-1, "app can't be null or empty");
} }
@ -137,7 +150,9 @@ public class SystemController {
@ResponseBody @ResponseBody
@RequestMapping("/save.json") @RequestMapping("/save.json")
Result<?> updateIfNotNull(Long id, String app, Double avgLoad, Long avgRt, Long maxThread, Double qps) { Result<?> updateIfNotNull(HttpServletRequest request,
Long id, String app, Double avgLoad, Long avgRt, Long maxThread, Double qps) {
AuthUser authUser = authService.getAuthUser(request);
if (id == null) { if (id == null) {
return Result.ofFail(-1, "id can't be null"); return Result.ofFail(-1, "id can't be null");
} }
@ -145,6 +160,7 @@ public class SystemController {
if (entity == null) { if (entity == null) {
return Result.ofFail(-1, "id " + id + " dose not exist"); return Result.ofFail(-1, "id " + id + " dose not exist");
} }
authUser.authTarget(entity.getApp(), PrivilegeType.WRITE_RULE);
if (StringUtil.isNotBlank(app)) { if (StringUtil.isNotBlank(app)) {
entity.setApp(app.trim()); entity.setApp(app.trim());
} }
@ -188,7 +204,8 @@ public class SystemController {
@ResponseBody @ResponseBody
@RequestMapping("/delete.json") @RequestMapping("/delete.json")
Result<?> delete(Long id) { Result<?> delete(HttpServletRequest request, Long id) {
AuthUser authUser = authService.getAuthUser(request);
if (id == null) { if (id == null) {
return Result.ofFail(-1, "id can't be null"); return Result.ofFail(-1, "id can't be null");
} }
@ -196,6 +213,7 @@ public class SystemController {
if (oldEntity == null) { if (oldEntity == null) {
return Result.ofSuccess(null); return Result.ofSuccess(null);
} }
authUser.authTarget(oldEntity.getApp(), PrivilegeType.DELETE_RULE);
try { try {
repository.delete(id); repository.delete(id);
} catch (Throwable throwable) { } catch (Throwable throwable) {

View File

@ -18,6 +18,11 @@ package com.alibaba.csp.sentinel.dashboard.controller.v2;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletRequest;
import com.alibaba.csp.sentinel.dashboard.service.AuthService;
import com.alibaba.csp.sentinel.dashboard.service.AuthService.AuthUser;
import com.alibaba.csp.sentinel.dashboard.service.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity; import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
@ -25,6 +30,7 @@ import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemoryRuleRepository
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider; import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher; import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.dashboard.domain.Result; import com.alibaba.csp.sentinel.dashboard.domain.Result;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -61,8 +67,14 @@ public class FlowControllerV2 {
@Qualifier("flowRuleDefaultPublisher") @Qualifier("flowRuleDefaultPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher; private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
@Autowired
private AuthService<HttpServletRequest> authService;
@GetMapping("/rules") @GetMapping("/rules")
public Result<List<FlowRuleEntity>> apiQueryMachineRules(@RequestParam String app) { public Result<List<FlowRuleEntity>> apiQueryMachineRules(HttpServletRequest request, @RequestParam String app) {
AuthUser authUser = authService.getAuthUser(request);
authUser.authTarget(app, PrivilegeType.READ_RULE);
if (StringUtil.isEmpty(app)) { if (StringUtil.isEmpty(app)) {
return Result.ofFail(-1, "app can't be null or empty"); return Result.ofFail(-1, "app can't be null or empty");
} }
@ -129,7 +141,10 @@ public class FlowControllerV2 {
} }
@PostMapping("/rule") @PostMapping("/rule")
public Result<FlowRuleEntity> apiAddFlowRule(@RequestBody FlowRuleEntity entity) { public Result<FlowRuleEntity> apiAddFlowRule(HttpServletRequest request, @RequestBody FlowRuleEntity entity) {
AuthUser authUser = authService.getAuthUser(request);
authUser.authTarget(entity.getApp(), PrivilegeType.WRITE_RULE);
Result<FlowRuleEntity> checkResult = checkEntityInternal(entity); Result<FlowRuleEntity> checkResult = checkEntityInternal(entity);
if (checkResult != null) { if (checkResult != null) {
return checkResult; return checkResult;
@ -151,7 +166,10 @@ public class FlowControllerV2 {
} }
@PutMapping("/rule/{id}") @PutMapping("/rule/{id}")
public Result<FlowRuleEntity> apiUpdateFlowRule(@PathVariable("id") Long id, @RequestBody FlowRuleEntity entity) { public Result<FlowRuleEntity> apiUpdateFlowRule(HttpServletRequest request,
@PathVariable("id") Long id,
@RequestBody FlowRuleEntity entity) {
AuthUser authUser = authService.getAuthUser(request);
if (id == null || id <= 0) { if (id == null || id <= 0) {
return Result.ofFail(-1, "Invalid id"); return Result.ofFail(-1, "Invalid id");
} }
@ -162,6 +180,8 @@ public class FlowControllerV2 {
if (entity == null) { if (entity == null) {
return Result.ofFail(-1, "invalid body"); return Result.ofFail(-1, "invalid body");
} }
authUser.authTarget(oldEntity.getApp(), PrivilegeType.WRITE_RULE);
entity.setApp(oldEntity.getApp()); entity.setApp(oldEntity.getApp());
entity.setIp(oldEntity.getIp()); entity.setIp(oldEntity.getIp());
entity.setPort(oldEntity.getPort()); entity.setPort(oldEntity.getPort());
@ -188,7 +208,8 @@ public class FlowControllerV2 {
} }
@DeleteMapping("/rule/{id}") @DeleteMapping("/rule/{id}")
public Result<Long> apiDeleteRule(@PathVariable("id") Long id) { public Result<Long> apiDeleteRule(HttpServletRequest request, @PathVariable("id") Long id) {
AuthUser authUser = authService.getAuthUser(request);
if (id == null || id <= 0) { if (id == null || id <= 0) {
return Result.ofFail(-1, "Invalid id"); return Result.ofFail(-1, "Invalid id");
} }
@ -196,6 +217,7 @@ public class FlowControllerV2 {
if (oldEntity == null) { if (oldEntity == null) {
return Result.ofSuccess(null); return Result.ofSuccess(null);
} }
authUser.authTarget(oldEntity.getApp(), PrivilegeType.DELETE_RULE);
try { try {
repository.delete(id); repository.delete(id);
publishRules(oldEntity.getApp()); publishRules(oldEntity.getApp());

View File

@ -0,0 +1,111 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.dashboard.service;
/**
* Interface about authentication and authorization
*
* @author Carpenter Lee
*/
public interface AuthService<R> {
/**
* Get the authentication user.
*
* @param request the request contains the user information
* @return the auth user represent the current user, when the user is illegal, a null value will return.
*/
AuthUser getAuthUser(R request);
/**
* privilege type.
*/
enum PrivilegeType {
/**
* read rule
*/
READ_RULE,
/**
* create or modify rule
*/
WRITE_RULE,
/**
* delete rule
*/
DELETE_RULE,
/**
* read metrics
*/
READ_METRIC,
/**
* add machine
*/
ADD_MACHINE,
/**
* equals all privileges above
*/
ALL
}
/**
* entity represents the current user
*/
interface AuthUser {
/**
* query whether current user has the specific privilege to the target, the target
* may be an app name or an ip address, or other destination.
* <p>
* This method will use return value to represent whether user has the specific
* privileges to the target, but to throw a RuntimeException to represent no auth
* is also a good way.
* </p>
*
* @param target the target to check
* @param privilegeType the privilege type to check
* @return if current user has the specific privileges to the target, return true,
* otherwise return false.
*/
boolean authTarget(String target, PrivilegeType privilegeType);
/**
* check whether current user is super user
*
* @return if current user is super user return true, else return false.
*/
boolean isSuperUser();
/**
* get current user's nick name.
*
* @return current user's nick name.
*/
String getNickName();
/**
* get current user's login name.
*
* @return current user's login name.
*/
String getLoginName();
/**
* get current user's employ id.
*
* @return current user's employ id.
*/
String getEmpId();
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.dashboard.service;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
/**
* A fake AuthService implementation, which will pass all user auth checking.
*
* @author Carpenter Lee
*/
@Component
public class FakeAuthServiceImpl implements AuthService<HttpServletRequest> {
@Override
public AuthUser getAuthUser(HttpServletRequest request) {
return new AuthUserImpl();
}
static final class AuthUserImpl implements AuthUser {
@Override
public boolean authTarget(String target, PrivilegeType privilegeType) {
// fake implementation, always return true
return true;
}
@Override
public boolean isSuperUser() {
// fake implementation, always return true
return true;
}
@Override
public String getNickName() {
return "FAKE_NICK_NAME";
}
@Override
public String getLoginName() {
return "FAKE_LOGIN_NAME";
}
@Override
public String getEmpId() {
return "FAKE_EMP_ID";
}
}
}