繁体   English   中英

Spring Security 总是返回 403 forbidden, Access denied

[英]Spring Security Always returning 403 forbidden, Access denied

我想让管理员访问管理页面并执行管理操作,但是当我尝试通过设置带有 /admin/** 的 url 只能由具有 admin 角色的用户访问来执行此操作时,它返回 403 Forbidden, access denied。 但是我检查了用户的权限设置为 ROLE_ADMIN。 我究竟做错了什么?

我的用户登录控制器

@RestController
public class UserController {

    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private AuthorityService authorityService;

    @Autowired
    private UserAuthorityService userAuthorityService;

    @Autowired
    TokenUtils tokenUtils;

    @Autowired
    private UserService userService;

    @RequestMapping(value = "/api/login", method = RequestMethod.POST, produces = "text/html")
    public ResponseEntity<String> login(@RequestBody LoginDTO loginDTO) {
        try {
//          System.out.println(loginDTO.getUsername() + " " + loginDTO.getPassword());
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
                    loginDTO.getUsername(), loginDTO.getPassword());

            Authentication authentication = authenticationManager.authenticate(token);

            SecurityContextHolder.getContext().setAuthentication(authentication);

            UserDetails details = userDetailsService.loadUserByUsername(loginDTO.getUsername());

            return new ResponseEntity<String>(tokenUtils.generateToken(details), HttpStatus.OK);
        } catch (Exception ex) {
            return new ResponseEntity<String>("Invalid login", HttpStatus.BAD_REQUEST);
        }
    }

    @RequestMapping(value = "/api/register", method = RequestMethod.POST, produces = "text/html")
    public ResponseEntity<String> register(@RequestBody RegisterDTO registerDTO) {
        try {
            System.out.println(registerDTO);
            User user = userService.findUserByUsername(registerDTO.getUsername());
//            // Check if user with that username exists
            if(user != null){
                // User with that username is found
                return new ResponseEntity<String>("User with that username exists", HttpStatus.BAD_REQUEST);
            }
            // We need to save the user so his ID is generated
            User newUser = userService.saveUser(new User(registerDTO));

            UserAuthority userAuthority = userAuthorityService.save(new UserAuthority(newUser, authorityService.findOneByName("User")));

            Set<UserAuthority> authorities = new HashSet<>();
            authorities.add(userAuthority);

            newUser.setUserAuthorities(authorities);
            User savedUser = userService.save(newUser);
            return new ResponseEntity<String>("You have registered successfully with username " + savedUser.getUsername(), HttpStatus.OK);
        } catch (Exception ex) {
            return new ResponseEntity<String>("Invalid register", HttpStatus.BAD_REQUEST);
        }
    }
}

我可以说我用邮递员测试我的应用程序并且登录和注册工作正常。 当用户登录时,我可以使用正确的数据和用户权限获取令牌,但是为什么当我尝试访问 /admin/building/add url 时它返回 403 错误?

我的用于为管理页面添加建筑物的控制器:

@RestController
public class BuildingController {

    @Autowired
    private BuildingService buildingService;

    @RequestMapping(value = "/admin/building/add", method = RequestMethod.POST, produces = "text/html")
    public ResponseEntity<String> addBuilding(@RequestBody BuildingDTO buildingDTO) {
        try{
            Building newBuilding = new Building(buildingDTO);
            return new ResponseEntity<String>(newBuilding.getName(), HttpStatus.OK);
        }catch (Exception ex) {
            return new ResponseEntity<String>("Data was not valid", HttpStatus.BAD_REQUEST);
        }
    }
}

我的安全配置.java

@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    public void configureAuthentication(
            AuthenticationManagerBuilder authenticationManagerBuilder)
            throws Exception {

        authenticationManagerBuilder
                .userDetailsService(this.userDetailsService).passwordEncoder(
                        passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public AuthenticationTokenFilter authenticationTokenFilterBean()
            throws Exception {
        AuthenticationTokenFilter authenticationTokenFilter = new AuthenticationTokenFilter();
        authenticationTokenFilter
                .setAuthenticationManager(authenticationManagerBean());
        return authenticationTokenFilter;
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
            .authorizeRequests()
                .antMatchers("/index.html", "/view/**", "/app/**", "/", "/api/login", "/api/register").permitAll()
                // defined Admin only API area 
                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest()
                .authenticated()
                .and().csrf().disable();
                //if we use AngularJS on client side
//              .and().csrf().csrfTokenRepository(csrfTokenRepository()); 

        //add filter for adding CSRF token in the request 
        httpSecurity.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);

        // Custom JWT based authentication
        httpSecurity.addFilterBefore(authenticationTokenFilterBean(),
                UsernamePasswordAuthenticationFilter.class);
    }

    /**
     * If we use AngularJS as a client application, it will send CSRF token using 
     * name X-XSRF token. We have to tell Spring to expect this name instead of 
     * X-CSRF-TOKEN (which is default one)
     * @return
     */
    private CsrfTokenRepository csrfTokenRepository() {
          HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
          repository.setHeaderName("X-XSRF-TOKEN");
          return repository;
    }
  }

我应该提到我在前端使用 Angularjs,但即便如此,我仍然可以登录并为该用户显示正确的权限。 但是由于某种原因,即使我以管理员身份登录,我也无法访问管理页面。

我还尝试了.hasAuthority("ROLE_ADMIN").hasRole("ROLE_ADMIN") (显示 ROLE_ 的错误),所以我将其更改为.hasRole("ADMIN")但它仍然无法正常工作。

在数据库中,admin 的角色保存为 ROLE_ADMIN。

像这样尝试:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private static String REALM="MY_TEST_REALM";

    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("bill").password("abc123").roles("ADMIN");
        auth.inMemoryAuthentication().withUser("tom").password("abc123").roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

      http.csrf().disable()
        .authorizeRequests()
        .antMatchers("/user/**").hasRole("ADMIN")
        .and().httpBasic().realmName(REALM).authenticationEntryPoint(getBasicAuthEntryPoint())
        .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);//We don't need sessions to be created.
    }

    @Bean
    public CustomBasicAuthenticationEntryPoint getBasicAuthEntryPoint(){
        return new CustomBasicAuthenticationEntryPoint();
    }

    /* To allow Pre-flight [OPTIONS] request from browser */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
    }
}

对于完整的配置示例: 使用基本身份验证的 Secure Spring REST API

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();// We don't need sessions to be created.
    }

}

这为我做到了。 现在我可以成功提交我的帖子请求了

在 SecurityConfig 中试试这个:

.antMatchers("/api/admin").access("hasRole('ADMIN')")
.antMatchers("/api/user").access("hasRole('ADMIN') or hasRole('USER')")

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM