英文:
Achieve Dynamic REST Resource specific Authorization
问题
我们有一个基于SpringBoot的模块,我们有REST API,允许使用参数创建资源
请求
POST /resources
{
"resourceName": "Res1",
"admins": ["john.doe@company.com", "jane.doe@company.com"]
}
响应
{
"id": "R1",
"resourceName": "Res1",
"admins": ["john.doe@company.com", "jane.doe@company.com"]
}
请求
POST /resources
{
"resourceName": "Res2",
"admins": ["alice@company.com", "bob@company.com"]
}
响应
{
"id": "R2",
"resourceName": "Res2",
"admins": ["alice@company.com", "bob@company.com"]
}
对于R1
的更新API只能由John/Jane访问
请求
PUT /resources/R1
{
"resourceName": "Resource1",
"admins": ["john.doe@company.com", "jane.doe@company.com", "jacob@company.com"]
}
响应
对于John/Jane,响应应为:
{
"id": "R1",
"resourceName": "Resource1",
"admins": ["john.doe@company.com", "jane.doe@company.com", "jacob@company.com"]
}
当Alice/Bob用户更新R1
时,响应应为403 Forbidden
类似地,对于R2
的更新API只能由Alice/Bob访问
当John/Jane更新R2
时,响应应为403 Forbidden
请建议使用哪个框架来实现这一点,最好是减少样板代码
目前,我们有一个资源访问的系统,采用基于角色的访问控制(Role-Based Access Control,RBAC)的形式。我们通过存储权限来实现限制。RBAC配置保存在数据库中。
但现在我们需要更细粒度的每个资源的控制,这可以由现有管理员直接管理。
英文:
We have a SpringBoot based module, we have REST APIs which allow creating resources with Params like
Request
POST /resources
{
"resourceName": "Res1",
"admins": ["john.doe@company.com", "jane.doe@company.com"]
}
Response
{
"id": "R1"
"resourceName": "Res1",
"admins": ["john.doe@company.com", "jane.doe@company.com"]
}
Request
POST /resources
{
"resourceName": "Res2",
"admins": ["alice@company.com", "bob@company.com"]
}
Response
{
"id": "R2"
"resourceName": "Res2",
"admins": ["alice@company.com", "bob@company.com"]
}
For R1
update API should only be accesible by John/Jane
Request
PUT /resources/R1
{
"resourceName": "Resource1",
"admins": ["john.doe@company.com", "jane.doe@company.com", "jacob@company.com"]
}
Response
For John / Jane the response should be:
{
"id": "R1"
"resourceName": "Resource1",
"admins": ["john.doe@company.com", "jane.doe@company.com", "jacob@company.com"]
}
When Alice / Bob user are updating R1
this response should be 403 Forbidden
Similarly For R2
update API should only be accesible by Alice / Bob.
When John / Jane are updating R2
this response should be 403 Forbidden
Please suggest which framework can be used to achieve this, preferably with less boiler plate
Currently we have a system where resource access is in for of RoleBasedAccessControl.
We achieve restriction by storing permissions. The RBAC config is saved in DB.
But now we need more fine grained control per resource which can be managed directly by existing admins
答案1
得分: 0
你可以在这种情况下使用Spring Security。
通常建议为用户分配角色以提高可维护性。
例如,分配管理员角色给 - john.doe@company.com、jane.doe@company.com,然后使用角色管理访问。
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
// 为用户分配角色
private static final String ROLE_1 = "ADMIN";
private static final String ROLE_2 = "USER";
// 在内存中配置用户和角色
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("john.doe@company.com")
.password(passwordEncoder().encode("admin@123"))
.roles(ROLE_1)
.and()
.withUser("jane.doe@company.com")
.password(passwordEncoder().encode("admin@12345"))
.roles(ROLE_1)
.and()
.withUser("user")
.password(passwordEncoder().encode("user@123"))
.roles(ROLE_2);
}
// 密码编码
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// 基于角色授权请求
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources/**").hasRole(ROLE_1)
.antMatchers("/all").permitAll()
.and().formLogin();
}
}
英文:
You could use Spring Security for this use case.
As a general practice it is recommended to assign roles for users for maintability.
For example assign admin role to - john.doe@company.com, jane.doe@company.com then manage the access using the role.
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
// Roles for users
private static final String ROLE_1 = "ADMIN";
private static final String ROLE_2 = "USER";
// In-memory users with roles
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("john.doe@company.com")
.password(passwordEncoder().encode("admin@123"))
.roles(ROLE_1)
.and()
.withUser("jane.doe@company.com")
.password(passwordEncoder().encode("admin@12345"))
.roles(ROLE_1)
.and()
.withUser("user")
.password(passwordEncoder().encode("user@123"))
.roles(ROLE_2);
}
// Password encoding
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// Authorized the request based on role
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources/**").hasRole(ROLE_1)
.antMatchers("/all").permitAll()
.and().formLogin();
}
}
答案2
得分: 0
这可以通过使用SpringBoot的方法级安全性来实现。
首先,通过对配置类进行注释来启用方法级安全性,如下所示 -
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class GlobalMethodConfig extends GlobalMethodSecurityConfiguration
然后提供PermissionEvaluator
类的实现,如下所示 -
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, Object permission) {
if (permission.equals("RESOURCE_WRITE_AUTHORITY")) {
Resource res = resourceRepository.getResourceById((String) targetId);
if (env != null) {
return env.getAdmins().contains(authentication.getName());
}
}
return false;
}
然后,您可以在控制器中对PUT方法或服务中的相应方法进行注释,以使用PermissionEvaluator,如下所示 -
@PreAuthorize("hasPermission(#resourceName, 'RESOURCE_WRITE_AUTHORITY')")
public Environment updateResource(String resourceName)
英文:
This can be achieved using a method level security from SpringBoot.
First enable Method Level Security by annotating a Config class like -
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class GlobalMethodConfig extends GlobalMethodSecurityConfiguration
Then provide an implementation of PermissionEvaluator
class like -
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, Object permission) {
if (permission.equals("RESOURCE_WRITE_AUTHORITY")) {
Resource res = resourceRepository.getResourceById((String) targetId);
if(env != null) {
return env.getAdmins().contains(authentication.getName());
}
}
return false;
}
After which you can annotate your PUT method in controller or the corresponding method in the service, to use PermissionEvaluator, like
@PreAuthorize("hasPermission(#resourceName, 'RESOURCE_WRITE_AUTHORITY')")
public Environment updateResource(String resourceName)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论