hasRole 和 hasAuthority 差在哪?ROLE_ 前缀什么时候要写?规则顺序写反了会怎样?角色继承怎么配?怎么写一个自己的授权决策?这篇在 Spring Boot 4.0.8、Spring Security 7 上用三个用户逐一验证。
规则:/user hasRole(USER);/admin hasRole(ADMIN);/byauth hasAuthority(ROLE_ADMIN);/noprefix hasAuthority(ADMIN);/either hasAnyRole(USER, ADMIN)
GET /user alice→200;root→403;eve→403
GET /admin alice→403;root→200;eve→403
GET /byauth alice→403;root→200;eve→403
GET /noprefix alice→403;root→403;eve→200
GET /either alice→200;root→200;eve→403
hasRole("ROLE_ADMIN"):应用启动失败:Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'chain' defined in demo.Main: Failed to instantiate [org.springframework.security.web.SecurityFilterChain]: Factory method 'chain' threw exception with message: ROLE_ADMIN should not start with ROLE_ since ROLE_ is automatically prepended when using hasAnyRole. Consider using hasAnyAuthority instead. | Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.web.SecurityFilterChain]: Factory method 'chain' threw exception with message: ROLE_ADMIN should not start with ROLE_ since ROLE_ is automatically prepended when using hasAnyRole. Consider using hasAnyAuthority instead.hasRole("X") 就是 hasAuthority("ROLE_X");写成 hasRole("ROLE_X") 启动失败。
正确顺序:先 /a/admin/** hasRole(ADMIN),再 /a/** hasRole(USER):
GET /a/x alice→200;root→403;eve→403
GET /a/admin/x alice→403;root→200;eve→403
写反:先 /a/** hasRole(USER),再 /a/admin/** hasRole(ADMIN):
GET /a/x alice→200;root→403;eve→403
GET /a/admin/x alice→200;root→403;eve→403
anyRequest().authenticated() 写在前面,后面又写 requestMatchers("/admin"):应用启动失败:Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'chain' defined in demo.Main: Failed to instantiate [org.springframework.security.web.SecurityFilterChain]: Factory method 'chain' threw exception with message: Can't configure requestMatchers after anyRequest | Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.web.SecurityFilterChain]: Factory method 'chain' threw exception with message: Can't configure requestMatchers after anyRequest第一个匹配的生效;具体的规则要写在宽泛的前面;anyRequest 之后不能再写。
没有 RoleHierarchy:/user 需要 hasRole(USER):
GET /user alice→200;root→403;eve→403
声明 RoleHierarchy bean "ROLE_ADMIN > ROLE_USER":
GET /user alice→200;root→200;eve→403
GET /admin alice→403;root→200;eve→403
自定义 AuthorizationManager(只允许本机、带 X-Internal: yes、并且用户是 alice):
GET /custom 用户 alice,头 {'X-Internal': 'yes'} → 200
GET /custom 用户 alice,头 {} → 403
GET /custom 用户 root,头 {'X-Internal': 'yes'} → 403
服务端记录的 custom manager 调用:
custom manager:用户=alice,远端=127.0.0.1,X-Internal=yes → true
custom manager:用户=alice,远端=127.0.0.1,X-Internal=null → false
custom manager:用户=root,远端=127.0.0.1,X-Internal=yes → falseRoleHierarchy bean 让高级角色拥有低级角色;AuthorizationManager 可以按请求与用户自定义。