首页 > 解决方案 > 在基于 Spring Security 角色的身份验证和授权中获取 Forbidden 错误

问题描述

我正在尝试学习 Spring 安全性,但我遇到了基于角色的安全性问题。

有 2 个表UserRole具有一对多的关系。

当我以 Spring 默认形式输入用户名和密码时,我通过 loadUserByUserName() 方法成功获取了正确的用户详细信息。但在屏幕上我收到一条消息

此应用程序没有显式映射 /error,因此您将其视为后备。

出现意外错误(类型=禁止,状态=403)。禁止的

只有 @GetMapping("/user") 方法可以正常工作。

这是控制器部分

@RestController
@RequestMapping("/admin")
public class AdminController {
    
    @Autowired
    UserRepository userRepo;

    @Autowired
    RoleRepository roleRepo;
    
    @PreAuthorize("hasAnyRole('ADMIN')")
    @PostMapping("/add")
 
    public String addUserByAdmin(@RequestBody User user)
    {
        user.getRoles().forEach(role -> role.setUser(user));
        userRepo.save(user);
        return "User added Successfully";
    }

        @PreAuthorize("hasAnyRole('ADMIN')")
        @GetMapping("/process")
        public String process()
        {
            return "Processing....";
        }
    
        @GetMapping("/user")
        public String users()            // This code is working properly
        {
            System.out.println("U r in user area's");
            return "User's space";
        }
}
   

配置部分

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableJpaRepositories(basePackageClasses = UserRepository.class)

public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    protected void configure(HttpSecurity http)throws Exception
    {
       http.csrf().disable();
       http.authorizeRequests()
           .antMatchers("/admin/**").authenticated()
           .anyRequest().permitAll()
           .and()
           .formLogin().permitAll(); 
    }
}
   

服务部分

@Service
public class CustomeUserDetailsService implements UserDetailsService
{
    @Autowired
    UserRepository userRepo;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
       
        User u = userRepo.findByName(username);
        
        CustomeUserDetails cUserDetails = new CustomeUserDetails();

        if(u == null)
        {
            throw new  UsernameNotFoundException("User "+username +"not found");
        }
        else
        {
            cUserDetails.setUser(u);
        }
        return cUserDetails;
    }
        
}
    

我哪里错了?
如果我想再添加一个不需要任何身份验证和授权的 URL,如何添加呢?

标签: springspring-bootspring-securityspring-data-jpa

解决方案


我认为您应该使用“ROLE_ADMIN”而不是“ADMIN”。“ROLE_ADMIN”键可以保存在数据库中并变成Collection。下面我是怎么做的。


实现用户详细信息的类

public class UsuarioSS implements LdapUserDetails {

private static final long serialVersionUID = 1164806375870272028L;
private String cdusuariorede;
private Collection<GrantedAuthority> authorities;

public UsuarioSS() {

}

public UsuarioSS(String cdusuariorede,List<Perfil> perfis) {
    super();
    this.cdusuariorede = cdusuariorede;
    this.authorities = new ArrayList<GrantedAuthority>();
    for (Perfil perfil : perfis) {
        this.authorities.add(new SimpleGrantedAuthority(perfil.toString()));
    }
}

public String getId() {
    return cdusuariorede;
}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    return authorities;
}

@Override
public String getPassword() {
    return null;
}

@Override
public String getUsername() {
    return cdusuariorede;
}

@Override
public boolean isAccountNonExpired() {
    return true;
}

@Override
public boolean isAccountNonLocked() {
    return true;
}

@Override
public boolean isCredentialsNonExpired() {
    return true;
}

@Override
public boolean isEnabled() {
    return true;
}

public boolean hasRole(String springSecurityKey) {
    return getAuthorities().contains(new SimpleGrantedAuthority(springSecurityKey));
}


@Override
public void eraseCredentials() {
    // TODO Auto-generated method stub
    
}

@Override
public String getDn() {
    // TODO Auto-generated method stub
    return null;
}

}


代表我的用户配置文件的枚举(AUTHORITHYES)

public enum Perfil {
ROLE_ADMIN,ROLE_DEFAULT

}


授权过滤器

public class JWTAuthorizationFilter extends BasicAuthenticationFilter {

private JWTUtil jwtUtil;
private UserDetailsService userDetailsService;

public JWTAuthorizationFilter(AuthenticationManager authenticationManager, JWTUtil jwtUtil,
        UserDetailsService userDetailsService) {
    super(authenticationManager);
    this.jwtUtil = jwtUtil;
    this.userDetailsService = userDetailsService;
}

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    String header = request.getHeader("Authorization");

    if (header != null && header.startsWith("Bearer ")) {
        UsernamePasswordAuthenticationToken auth = getAuthentication(header.substring(7));
        if (auth != null) {
            SecurityContextHolder.getContext().setAuthentication(auth);
        }
    }
    chain.doFilter(request, response);
}

private UsernamePasswordAuthenticationToken getAuthentication(String token) {
    if (jwtUtil.tokenValido(token)) {
        String login = jwtUtil.getLogin(token);
        UserDetails usuario = userDetailsService.loadUserByUsername(login);
        return new UsernamePasswordAuthenticationToken(usuario, null, usuario.getAuthorities());
    }
    return null;
}

}


我的控制器

@RestController

@RequestMapping(value = "/parte") 公共类 ParteController {

@Autowired
private ParteService service;

@PreAuthorize("hasAnyRole('ROLE_ADMIN')")
@GetMapping("/partes_demandadas_por_processo")
public ResponseEntity<List<TpPartesProcessoDto>> getPartesPorNuprocesso(
        @RequestParam(name = "processo",required = true)
        @Length(max = 15,min = 15,message = "O campo processo deve possuir 15 caracteres.")         
        String processo
        ) throws SQLException{
    List<TpPartesProcessoDto> partes = service.getPartesdoProcessoPorNuprocesso(processo);      
    return ResponseEntity.ok().body(partes);
}

}


推荐阅读