无法实现对 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。我尝试使用 @PreAuthorizeantMatchers & 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的参数

基于spring-boot的应用程序的单元+集成测试方案

使用 Google Cloud Pub/Sub 消息订阅者实现时无法创建 Spring-Boot bean

如何在spring-boot应用程序的junit中调用ApplicationContextInitializer