Я разработал REST api, в котором методы защищены SpringSecurity.
ССЫЛКА НА GITHUB-> Проект
Он работает, но не так, как ожидалось
SpringSecurity.config
---------------------------
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private UserDetailsService userDetailService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailService).passwordEncoder(encode());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable();
http
.authorizeRequests()
.antMatchers("/user/**")
.authenticated()
.anyRequest()
.hasAnyRole("USER","ADMIN")
.and()
.authorizeRequests()
.antMatchers("/admin/**")
.authenticated()
.anyRequest()
.hasRole("ADMIN")
.and()
.formLogin()
.permitAll();
/*http
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasAnyRole("USER","ADMIN")
.anyRequest()
.authenticated()
.and()
.formLogin()
.permitAll();*/
}
@Bean
public BCryptPasswordEncoder encode() {
return new BCryptPasswordEncoder();
}
}
Админконтроллер
----------------------
@RestController
@RequestMapping("/admin")
public class AdminController {
@Autowired
private UserRepo userRepo;
@Autowired
private BCryptPasswordEncoder encoder;
@PostMapping("/add")
@PreAuthorize("hasRole('ADMIN')")
public String addUser(@RequestBody User user) {
String encodedPwd= encoder.encode(user.getPassword());
user.setPassword(encodedPwd);
userRepo.save(user);
return "user added sucessfully...";
}
@GetMapping("/demo")
@PreAuthorize("hasRole('ADMIN')")
public String getDemo() {
return "Hi";
}
}
CustomController
-------------------------
@RestController
@RequestMapping("/user")
public class CustomController {
@GetMapping("/access")
@PreAuthorize("hasAnyRole('USER','ADMIN')")
public String showUser() {
return "Url Security Provided";
}
}
CustomUserDetailService
-----------------------------
@Service
public class CustomUserDetailService implements UserDetailsService {
@Autowired
private UserRepo userRepo;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user= userRepo.findByUsername(username);
CustomUserDetails userDetails= null;
if (user!= null) {
userDetails= new CustomUserDetails();
userDetails.setUser(user);
}else {
throw new UsernameNotFoundException("User Not Found");
}
return userDetails;
}
}
CustomUserDetail
-----------------
@Getter
@Setter
public class CustomUserDetails implements UserDetails {
/**
*
*/
private static final long serialVersionUID = 1L;
private User user;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
/*return user.getRoles().stream()
.map(role->new SimpleGrantedAuthority("ROLE_"+ role))
.collect(Collectors.toList());*/
return user.getRoles().stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role))
.collect(Collectors.toList());
}
@Override
public String getPassword() {
// TODO Auto-generated method stub
return user.getPassword();
}
@Override
public String getUsername() {
// TODO Auto-generated method stub
return user.getUsername();
}
@Override
public boolean isAccountNonExpired() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean isEnabled() {
// TODO Auto-generated method stub
return true;
}
public CustomUserDetails() {
super();
// TODO Auto-generated constructor stub
}
}
Пользователь
----------
@Entity
@Getter
@Setter
@NoArgsConstructor
public class User {
@Id
@GenericGenerator(name = "gen",strategy = "increment")
@GeneratedValue(generator = "gen")
private int user_id;
private String username;
private String password;
private String email;
@OneToMany(cascade= CascadeType.ALL, fetch= FetchType.EAGER)
@JoinTable(name = "user_roles",
joinColumns= @JoinColumn(referencedColumnName= "user_id"),
inverseJoinColumns= @JoinColumn(referencedColumnName = "role_id"))
private Set<Roles> roles;
}
Проблема в:
С помощью вышеуказанной настройки я могу получить доступ к URL-адресу, который предназначен для ПОЛЬЗОВАТЕЛЯ, а не для ADMIN
Если я комментирую
http
/*.authorizeRequests()
.antMatchers("/user/**")
.authenticated()
.anyRequest()
.hasRole("USER")
.and()*/
.authorizeRequests()
.antMatchers("/admin/**")
.authenticated()
.anyRequest()
.hasRole("ADMIN")
.and()
.formLogin()
.permitAll();
Затем я могу получить доступ к URL, которые предназначены для АДМИНИСТРАТОР, но мне не хватает аутентификации на URL, которые предназначены для ПОЛЬЗОВАТЕЛЬ
Точно так же, если я комментирую админ /, тогда можно будет получить доступ к части ПОЛЬЗОВАТЕЛЬ. Он ведет себя как упорядочивание, который когда-либо находится в первом URL-адресе, он распознает это, а второй просто выдает 403 в браузере, а не в консоли.
Это что-то вроде Порядка, который первым доступен
Я где-нибудь делаю что-то не так?
Если я не буду комментировать @EnableGlobalSecurity, @PreAuthorize, я не могу получить доступ ни к одному из URL, которые предназначены для АДМИНИСТРАТОР и ПОЛЬЗОВАТЕЛЬ, просто 403, поэтому я не могу пропустить @EnableGlobalSecurity, @PreAuthorize, поскольку они предназначены для защиты методов REST API
Я уже пробовал это, в этом случае я не могу получить доступ к URL-адресу на основе ПОЛЬЗОВАТЕЛЯ или URL-адресу на основе ADMIN.
Даже если в консоли БД запросы запускаются, а в браузере просто 403
Это SPRING JPA, поэтому в userRepo у меня есть один метод, который загружает пользователя в соответствии с заданным именем пользователя.
Хотя вы говорите, что sql-запросы выполняются, это означает, что метод выполняется (и вы можете разместить указатель отладки и отладить метод для подтверждения), однако он возвращает 403 означает, что на высоком уровне что-то не так с @Postauthorize, но мы делаем не вижу никаких методов, аннотированных тем же, либо @Preauthorize комментируется в соответствии с вашим опубликованным кодом и, следовательно, не имеет отношения к @EnableGlobalMethodSecurity. можешь поделиться логами?
Как в базе данных выглядит сопоставление пользователя с ролью?
Проверьте сейчас. Я обновил вопрос, включив @EnableGlobalMethodSecurity (securedEnabled = true), @PreAuthorize и т. д.
Просто добавьте разрешение на все свои страницы для вашей роли администратора. Таким образом, вы убедитесь, что ваш администратор может получить доступ к любой странице, которую он хочет.
http
/*.authorizeRequests()
.antMatchers("/user/**")
.authenticated()
.anyRequest()
.hasRole("USER")
.and()*/
.authorizeRequests()
.antMatchers("/admin/**")
.hasRole("ADMIN")
.antMatchers("/user/**")
.hasAnyRole("ADMIN", "USER")
.and()
.formLogin()
.permitAll();
изменение его на
.antMatchers("/admin/**").hasAnyRole("ADMIN") .antMatchers("/user/**").hasAnyRole("USER")должно помочь. Вам не нужно звонитьauthorizeRequestsнесколько раз