Definition of Role and Authority
Role(角色):Role是一组权限(Authorities)的集合。
基于角色的访问控制(Role-Based Access Control, RBAC),用户被赋予不同的角色,角色与权限相关联。
Authority(权限):标识用户具有的具体权限。每个权限代表一个被授予的操作或资源访问的权限,权限包括一个接口、资源访问、系统的一个功能点。
Spring Security使用spring-boot-starter-security依赖时,默认基于权限而不是角色。
用户可以自定义实现基于角色的访问控制。
自定义角色
public class Authority {
private Long id;
private String name;
}
public class Role {
private Long id;
private String name;
private List<Authority> authorities;
}
public class UserInfo {
private Long id;
private List<Role> roles;
}
CREATE TABLE role_authority (
role_id BIGINT,
authority_id BIGINT,
PRIMARY KEY (role_id, authority_id)
);
CREATE TABLE user_role (
user_id BIGINT,
role_id BIGINT,
PRIMARY KEY (user_id, role_id)
);
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
@Component("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserInfo user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
return createSpringSecurityUser(user);
}
public User createSpringSecurityUser(UserInfo user) {
Set<GrantedAuthority> authorities = new ArrayList<>();
List<Role> roles = user.getRoles();
for(Role role:roles) {
for(Authority authority:role.getAuthorities()) {
authorities.add(new SimpleGrantedAuthority(authority.getName()));
}
}
authorities = authorities.stream().distinct().collect(Collectors.toList());
return new User(user.getUsername(), user.getPassword(), authorities);
}
}
注:上述代码中用户有可能有多个角色,不同角色可能有相同的权限,最后一步需要权限去重。
实例
TestController
@Slf4j
@RestController
@RequestMapping("/api/v1/version")
public class VersionController {
@GetMapping("/test1")
public String test1() {
return "test1";
}
@GetMapping("/test2")
public String test2() {
return "test2";
}
@GetMapping("/test3")
public String test3() {
return "test3";
}
@GetMapping("/test4")
public String test4() {
return "test4";
}
}
WebSecuirtyConfig
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.cors()
.and()
// we don't need CSRF because our token is invulnerable
.csrf().disable()
// set exception handler
.exceptionHandling()
.authenticationEntryPoint(authenticationErrorHandler)
.accessDeniedHandler(jwtAccessDeniedHandler)
// enable h2-console
.and()
.headers().frameOptions().disable().and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
// set URL for accessing free
.and()
.authorizeRequests()
.mvcMatchers(HttpMethod.GET, "/api/v1/version/test1").hasAnyAuthority("ROLE_DOC_GET", "ROLE_DOC_DELETE")
.mvcMatchers(HttpMethod.GET, "/api/v1/version/test2").hasAuthority("DOC_GET")
.mvcMatchers(HttpMethod.GET, "/api/v1/version/test3").hasRole("DOC_GET")
.mvcMatchers(HttpMethod.GET, "/api/v1/version/test4").hasAnyRole("DOC_GET", "DOC_DELETE")
.anyRequest().authenticated()
.and()
.apply(securityConfigurerAdapter());
}
用户角色-权限
运行结果
结论
- Authority = ROLE_ + Role
需要使用Authority作为Role时,DB设置时需要以ROLE_为前缀。
- 多角色的本质还是多权限,Spring Security默认基于权限处理。实际用户有多个角色时,判断使用hasAuthority/hasAnyAuthority更方便