为了演示组合模式实现权限验证的功能,我需要做以下几个步骤:
首先,创建一个Spring Boot项目,并添加spring-boot-starter-security依赖:
org.springframework.boot
spring-boot-starter-security
然后,创建一个简单的Controller类,提供两个受保护的资源:/admin和/user:
@RestController
public class HelloController {
@GetMapping("/admin")
public String admin() {
return "Hello, admin!";
}
@GetMapping("/user")
public String user() {
return "Hello, user!";
}
}
接着,创建一个SecurityConfig类,继承WebSecurityConfigurerAdapter,并配置自定义的AccessDecisionManager和AccessDecisionVoter:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// 配置自定义的AccessDecisionManager
http.authorizeRequests()
.anyRequest().authenticated()
.accessDecisionManager(customAccessDecisionManager());
}
// 定义一个Bean,返回一个CustomAccessDecisionManager对象,并注入两个CustomAccessDecisionVoter对象
@Bean
public AccessDecisionManager customAccessDecisionManager() {
List> voters = new ArrayList<>();
voters.add(new CustomAccessDecisionVoter1());
voters.add(new CustomAccessDecisionVoter2());
return new CustomAccessDecisionManager(voters);
}
// 在内存中配置一些用户和角色信息
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password("{noop}123").roles("ADMIN")
.and()
.withUser("user").password("{noop}123").roles("USER");
}
}
接下来,创建一个CustomAccessDecisionManager类,实现AccessDecisionManager接口,并注入一个AccessDecisionVoter列表:
public class CustomAccessDecisionManager implements AccessDecisionManager {
// 注入一个AccessDecisionVoter列表
private List> voters;
public CustomAccessDecisionManager(List> voters) {
this.voters = voters;
}
// 实现decide方法,根据投票结果决定是否授权访问
@Override
public void decide(Authentication authentication, Object object, Collection configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
// 定义一个变量,记录赞成票数
int grant = 0;
// 遍历所有的投票者,调用它们的vote方法,并根据返回值进行统计
for (AccessDecisionVoter voter : voters) {
int result = voter.vote(authentication, object, configAttributes);
switch (result) {
case AccessDecisionVoter.ACCESS_GRANTED:
grant++;
break;
case AccessDecisionVoter.ACCESS_DENIED:
throw new AccessDeniedException("访问被拒绝");
default:
break;
}
}
// 如果没有赞成票,则抛出异常
if (grant == 0) {
throw new AccessDeniedException("访问被拒绝");
}
}
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class> clazz) {
return true;
}
}
最后,创建两个CustomAccessDecisionVoter类,分别实现AccessDecisionVoter接口,并根据不同的逻辑进行投票:
public class CustomAccessDecisionVoter1 implements AccessDecisionVoter
public class CustomAccessDecisionVoter2 implements AccessDecisionVoter
这样,我们就用最简练的代码写出了一个使用组合模式实现权限验证的例子。您可以运行这个项目,并使用不同的用户和密码访问不同的资源。例如:
使用了两个CustomAccessDecisionVoter对象来组合一个CustomAccessDecisionManager对象,并通过它来决定一个请求是否能够访问受保护的资源。这就是使用组合模式实现权限验证的功能。