在之前的文章样例中,认证和授权都是基于 URL 的。开发者也可以通过注解来灵活地配置方法安全,下面通过样例进行演示。
十、通过注解配置方法安全
1、样例代码
(1)首先我们要通过 @EnableGlobalMethodSecurity 注解开启基于注解的安全配置:
@EnableGlobalMethodSecurity 注解参数说明:
- prePostEnabled = true 会解锁 @PreAuthorize 和 @PostAuthorize 两个注解。顾名思义,@PreAuthorize 注解会在方法执行前进行验证,而 @PostAuthorize 注解会在方法执行后进行验证。
- securedEnabled = true 会解锁 @Secured 注解。
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
// 指定密码的加密方式
@SuppressWarnings("deprecation")
@Bean
PasswordEncoder passwordEncoder(){
// 不对密码进行加密
return NoOpPasswordEncoder.getInstance();
}
// 配置用户及其对应的角色
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("root").password("123").roles("DBA")
.and()
.withUser("admin").password("123").roles("ADMIN")
.and()
.withUser("hangge").password("123").roles("USER");
}
// 配置 URL 访问权限
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() // 开启 HttpSecurity 配置
.anyRequest().authenticated() // 用户访问其它URL都必须认证后访问(登录后访问)
.and().formLogin().loginProcessingUrl("/login").permitAll() // 开启表单登录并配置登录接口
.and().csrf().disable(); // 关闭csrf
}
}
(2)开启注解安全配置后,接着创建一个 MethodService 进行测试:
@Service
public class MethodService {
// 访问该方法需要 ADMIN 角色。注意:这里需要在角色前加一个前缀"ROLE_"
@Secured("ROLE_ADMIN")
public String admin() {
return "hello admin";
}
// 访问该方法既要 ADMIN 角色,又要 DBA 角色
@PreAuthorize("hasRole('ADMIN') and hasRole('DBA')")
public String dba() {
return "hello dba";
}
// 访问该方法只需要 ADMIN、DBA、USER 中任意一个角色即可
@PreAuthorize("hasAnyRole('ADMIN','DBA','USER')")
public String user() {
return "hello user";
}
}
(3)最后在 Controller 中注入这个 Service 并调用 Service 中的方法进行测试:
@RestController
public class HelloController {
@Autowired
MethodService methodService;
@GetMapping("/admin")
public String admin() {
return methodService.admin();
}
@GetMapping("/dba")
public String dba() {
return methodService.dba();
}
@GetMapping("/user")
public String user() {
return methodService.user();
}
}
2、运行测试
(1)使用 admin 用户登录,无论访问 /admin 接口、还是 /user 接口都是没问题的:
(2)而对于 /dba 接口虽然 admin 也有权限,但该接口内部调用的 methodService.dba() 方法同时需要 ADMIN 和 DBA 权限,因此访问会被拒绝。