Spring Security 总是返回 403 forbidden, Access denied
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/47221666/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring Security Always returning 403 forbidden, Access denied
提问by P3P5
I want to enable admin to access admin page and do admin stuff, but when I try to do that by setting that the url with /admin/** can only be accessed by user with role admin, it returns 403 Forbidden, access denied. But the user has authorities set to ROLE_ADMIN I checked. What am I doing wrong?
我想让管理员访问管理页面并执行管理操作,但是当我尝试通过设置带有 /admin/** 的 url 只能由具有管理员角色的用户访问来执行此操作时,它返回 403 Forbidden, access denied。但是我检查了用户的权限设置为 ROLE_ADMIN。我究竟做错了什么?
My Controller for user login
我的用户登录控制器
@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);
}
}
}
I can say that I test my app with postman and login and registration are working fine. When the user is logged in I can the token with the correct data and users authorities, but why when I try to access /admin/building/add url it is returning 403 error?
我可以说我用邮递员测试我的应用程序并且登录和注册工作正常。当用户登录时,我可以使用正确的数据和用户权限获取令牌,但是为什么当我尝试访问 /admin/building/add url 时它返回 403 错误?
My Controller for adding building for admin page:
我的用于为管理页面添加建筑物的控制器:
@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);
}
}
}
My SecurityConfiguration.java
我的安全配置.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;
}
}
I should mention that I am using Angularjs for frontend, but even so I can login and the correct authorities are displayed for that user. But for some reason I can not access the admin page, even if I login as admin.
我应该提到我在前端使用 Angularjs,但即便如此,我仍然可以登录并为该用户显示正确的权限。但是由于某种原因,即使我以管理员身份登录,我也无法访问管理页面。
Also I tried .hasAuthority("ROLE_ADMIN")and .hasRole("ROLE_ADMIN")(which displays an error for ROLE_) and so I changed it to .hasRole("ADMIN")but it is still not working.
我也试过.hasAuthority("ROLE_ADMIN")和.hasRole("ROLE_ADMIN")(它显示了 ROLE_ 的错误),所以我将其更改为.hasRole("ADMIN")但它仍然无法正常工作。
In the database the role for admin is saved as ROLE_ADMIN.
在数据库中,admin 的角色保存为 ROLE_ADMIN。
回答by FuSsA
Try like this :
像这样尝试:
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, "/**");
}
}
For a complet configuration example : Secure Spring REST API using Basic Authentication
对于完整的配置示例:使用基本身份验证的 Secure Spring REST API
回答by Ajay Menon
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.
}
}
This did it for me. Now I am able to submit my post requests successfully
这为我做到了。现在我可以成功提交我的帖子请求了
回答by Hoang Quy
Try this in SecurityConfig:
在 SecurityConfig 中试试这个:
.antMatchers("/api/admin").access("hasRole('ADMIN')")
.antMatchers("/api/user").access("hasRole('ADMIN') or hasRole('USER')")

