无法实现对 Spring-Boot API 的基于角色的访问
Posted
技术标签:
【中文标题】无法实现对 Spring-Boot API 的基于角色的访问【英文标题】:Unable to implement Role based access to Spring-Boot API 【发布时间】:2019-12-11 00:18:34 【问题描述】:我是 Spring-Boot 的新手。我想创建一个 API,该 API 将具有基于角色的访问权限和基于 JWT 令牌的身份验证。但是,无法实现。
我没有使用 JPA 和 Hibernate 来获取和映射数据。相反,我使用的是 Ibatis。我尝试使用 @PreAuthorize 和 antMatchers & hasRole,但失败了。通过从 JWT 令牌获取用户 ID,我正在获取详细信息和角色并将其设置为 SecurityContextHolder.getContext().setAuthentication,但仍然无法正常工作。
安全配置
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilter(new JwtAuthorizationFilter(authenticationManager()))
.authorizeRequests()
.anyRequest().authenticated()
.antMatchers("api/management/reports").hasRole("Supervisor");
控制器
@RestController
@RequestMapping("api")
@CrossOrigin
public class MyController
@PreAuthorize("hasRole('Supervisor')")
@GetMapping("username")
public String reports()
SecurityContext securityContext = SecurityContextHolder.getContext();
return securityContext.getAuthentication().getName();
授权过滤器
public class JwtAuthorizationFilter extends BasicAuthenticationFilter
public JwtAuthorizationFilter(AuthenticationManager authenticationManager)
super(authenticationManager);
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException
String header = request.getHeader(JwtProperties.HEADER_STRING);
if (header == null || !header.startsWith(JwtProperties.TOKEN_PREFIX))
chain.doFilter(request, response);
return;
Authentication authentication = getUsernamePasswordAuthentication(request,header);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(request, response);
private Authentication getUsernamePasswordAuthentication(HttpServletRequest request, String header)
try
String token = header.replace(JwtProperties.TOKEN_PREFIX,"");
String userName = JWT.require(HMAC512(JwtProperties.SECRET.getBytes()))
.build()
.verify(token)
.getSubject();
List<User> searchedUserList = getUserDetailsDAO().getUserDetails(userName);
if (null !=searchedUserList && searchedUserList.size()>0)
User searchedUser = new User();
searchedUser = searchedUserList.get(0);
List<RoleAccess> roleAccessList = new ArrayList<RoleAccess>();
XrefUsrRole oXrefUsrRole = new XrefUsrRole();
oXrefUsrRole.setUserName(searchedUser.getUsername());
roleAccessList = getRoleAccessDAO().getAccessDetails(oXrefUsrRole);
List<GrantedAuthority> authorities = uildUserAuthority(roleAccessList);
org.springframework.security.core.userdetails.User newUser = buildUserForAuthentication(searchedUser, authorities);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(newUser, null,authorities);
return auth;
return null;
return null;
catch (IOException e)
return null;
private org.springframework.security.core.userdetails.User buildUserForAuthentication(User searchedUser, List<GrantedAuthority> authorities)
return new org.springframework.security.core.userdetails.User(searchedUser.getUsername(), searchedUser.getPassword(), true, true, true, true, authorities);
private List<GrantedAuthority> buildUserAuthority(List<RoleAccess> roleAccessList)
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
// Build user's authorities
for (RoleAccess userRole : roleAccessList)
setAuths.add(new SimpleGrantedAuthority("ROLE_"+userRole.getModifiedBy()));
List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);
return Result;
在这种情况下,除了具有 Supervisor 角色的用户外,不应访问 api/username。
【问题讨论】:
【参考方案1】:您有 ROLE_"+userRole.getModifiedBy()) 这意味着您正在授予具有 ROLE_NAME 的角色,并且在 PreAuthorize 中您有导致问题的主管。您可以将角色存储为 ROLE_SUPERVISOR 在数据库中,然后按如下方式使用它
// Build user's authorities
for (RoleAccess userRole : roleAccessList)
setAuths.add(new SimpleGrantedAuthority("ROLE_"+userRole.getModifiedBy()));
使用
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
.antMatchers("api/management/reports").hasRole("SUPERVISOR");
【讨论】:
你的意思是说数据库中的角色名会是ROLE_SUPERVISOR,那我在建权限的时候再加“ROLE_”?? 是的,将角色添加为 ROLE_SUPERVISOR 并在此处使用 hasRole(ROLENAME) hasRole(SUPERVISOR) 如果您遇到问题,请告诉我 谢谢@Patel Romil。我没有更改数据库中的角色名称,但使用 hasRole('ROLE_SUPERVISOR'),它现在可以工作了。以上是关于无法实现对 Spring-Boot API 的基于角色的访问的主要内容,如果未能解决你的问题,请参考以下文章
在 spring-boot 中删除其中一个 Web API 上的 Auth Filter
使用validator-api来验证spring-boot的参数
使用validator-api来验证spring-boot的参数