Пользователи Spring Security не получают роли - PullRequest
0 голосов
/ 06 января 2020

Прежде всего, вот моя Spring Security Configuration

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    AccountDetailsService accountDetailsService;

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

    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());

        http
                .authorizeRequests()
                .antMatchers("/api/getalltopics").hasRole("ADMIN")
                .antMatchers(HttpMethod.POST,"/api/createtopic").hasRole("ADMIN")
                .antMatchers("/me").permitAll()
                .antMatchers("/login").permitAll()
                .antMatchers("/logout").permitAll()
                .antMatchers("/getcsrftoken").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .defaultSuccessUrl("http://192.168.1.105:3000/", true)
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("http://192.168.1.105:3000/")
                .deleteCookies("JSESSIONID");
    }
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        //This is the password encoder that I will be using
        return new BCryptPasswordEncoder();
    }
}

, которая ведет меня прямо в мой AccountDetailsService

@Service("userDetailsService")
@Transactional
public class AccountDetailsService implements UserDetailsService {
    @Autowired
    AccountService accountService;

    @Override
    public UserDetails loadUserByUsername(String username){
        Account account = accountService.findAccountByUsername(username);

        //TODO: Check if user exists

        return new org.springframework.security.core.userdetails.User(
                account.getUsername(), account.getPassword(),
                account.isEnabled(), true, true, true,
                accountService.getAuthorities(account.getRoles()));
    }
}

, который снова приводит меня к моей учетной записи Service

@Service
public class AccountService {
    @Autowired
    AccountRepository accountRepository;

    @Autowired
    PrivilegeRepository privilegeRepository;

    @Autowired
    RoleRepository roleRepository;

    public Privilege findPrivilegeByName(String privilegeName){
        return privilegeRepository.findByName(privilegeName);
    }

    public void savePrivilege(Privilege privilege){
        privilegeRepository.save(privilege);
    }

    public Role findRoleByName(String roleName){
        return roleRepository.findByName(roleName);
    }

    public void saveRole(Role role){
        roleRepository.save(role);
    }

    public void saveAccount(Account account){
        accountRepository.save(account);
    }

    public Account findAccountByUsername(String username){
        return accountRepository.findByUsername(username);
    }

    public Collection<? extends GrantedAuthority> getAuthorities(Collection<Role> roles){
        return getGrantedAuthorities(getPrivileges(roles));
    }
    private List<String> getPrivileges(Collection<Role> roles){
        List<String> privileges = new ArrayList<>();
        List<Privilege> collection = new ArrayList<>();

        for(Role role : roles){
            collection.addAll(role.getPrivileges());
        }
        for(Privilege item : collection){
            privileges.add(item.getName());
        }
        return privileges;
    }
    private List<GrantedAuthority> getGrantedAuthorities(List<String> privileges){
        List<GrantedAuthority> authorities = new ArrayList<>();
        for (String privilege : privileges){
            authorities.add(new SimpleGrantedAuthority(privilege));
        }
        return authorities;
    }
}

А вот и моя сущность Аккаунта на всякий случай, когда это необходимо

@Entity
@Table(name="account")
public class Account extends TimeStampModel{
    // Extends TimeStampModel so we know when the user was created
    @Id
    @GeneratedValue
    @Column
    private Long id;

    @Column(nullable = false)
    private String username;

    @Column(nullable = false)
    private String password;

    @Column
    private int amountOfLikes;

    @Column
    private int amountOfDislikes;

    @OneToMany(cascade = CascadeType.ALL)
    private List<Comment> comments;

    @OneToMany(cascade = CascadeType.ALL)
    private List<Post> posts;

    private boolean isEnabled;

    private boolean isTokenExpired;

    @ManyToMany
    @JoinTable(
            name = "account_roles",
            joinColumns = @JoinColumn(
                    name = "account_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(
                    name = "role_id", referencedColumnName = "id"))
    private Collection<Role> roles;

    public Account(){}

    public Account(String username, String password, boolean isEnabled){
        this.username = username;
        this.password = password;
        this.amountOfDislikes = 0;
        this.amountOfLikes = 0;
        this.isEnabled = isEnabled;
    }

    //getters and setters omitted
}

Теперь моя проблема в том, что когда я создаю тестового пользователя и назначаю ему роль ADMIN, а позже я пытаюсь проверить, У пользователя есть роль, которую мне всегда возвращают ложным. Если я пытаюсь сделать несколько запросов на мой сервер с пользователем, я всегда получаю 403 Запрещено. Что я здесь не так делаю?

Вот мой класс, где я настроил тестового пользователя, и это тот пользователь, которого я использую, чтобы попытаться войти в систему

@Component
public class InitialDataLoader implements ApplicationListener<ContextRefreshedEvent> {
    boolean alreadySetup = false;

    @Autowired
    AccountService accountService;

    @Autowired
    PasswordEncoder passwordEncoder;

    @Override
    @Transactional
    public void onApplicationEvent(ContextRefreshedEvent event){
        //don't do any setup if it has already been done
        if(alreadySetup) return;

        Privilege readPrivilege = createPrivilegeIfNotFound("READ_PRIVILEGE");
        Privilege writePrivilege = createPrivilegeIfNotFound("WRITE_PRIVILEGE");

        List<Privilege> adminPrivileges = Arrays.asList(readPrivilege, writePrivilege);
        List<Privilege> userPrivileges = Arrays.asList(readPrivilege);

        createRoleIfNotFound("ROLE_ADMIN", adminPrivileges);
        createRoleIfNotFound("ROLE_USER", userPrivileges);

        Role adminRole = accountService.findRoleByName("ROLE_ADMIN");

        Account account = new Account("test", passwordEncoder.encode("123"), true);
        account.setRoles(Arrays.asList(adminRole));

        accountService.saveAccount(account);
        alreadySetup = true;
    }

    @Transactional
    Privilege createPrivilegeIfNotFound(String privilegeName){
        Privilege privilege = accountService.findPrivilegeByName(privilegeName);

        if(privilege == null){
            //if the privilege doesn't exist, we create one
            privilege = new Privilege(privilegeName);
            accountService.savePrivilege(privilege);
        }
        //if the privilege exists, just return it
        return privilege;
    }

    @Transactional
    Role createRoleIfNotFound(String roleName, Collection<Privilege> privilegeCollection){
        Role role = accountService.findRoleByName(roleName);

        if(role == null){
            //if the role doesn't exist, we create one
            role = new Role(roleName);
            role.setPrivileges(privilegeCollection);
            accountService.saveRole(role);
        }
        //if the role exists, just return it
        return role;
    }
}

Также у меня есть это отображение установить, кто проверяет, есть ли у пользователя какую-то роль, и они всегда возвращают false, если это помогает.

    @GetMapping("/me")
    public Principal getMe(SecurityContextHolderAwareRequestWrapper requestWrapper, Principal principal) {
        System.out.println(requestWrapper.isUserInRole("ADMIN"));
        System.out.println(requestWrapper.isUserInRole("ROLE_ADMIN"));
        return principal;
    }

Я просто не знаю, что делать дальше, я так потерян ..

Ответы [ 2 ]

1 голос
/ 06 января 2020

InitialDataLoader.createRoleIfNotFound() создает роли с привилегиями READ_PRIVILEGE и WRITE_PRIVILEGE

AccountService.getGrantedAuthorities() создает объекты SimpleGrantedAuthority на основе привилегий, а не для роли ADMIN.

This не позволяет Авторизации работать как положено. Создание SimpleGrantedAuthority объектов с необходимой ролью должно решить проблему авторизации здесь.

1 голос
/ 06 января 2020

Я думаю, прежде всего вы должны поставить @ EnableGlobalMethodSecurity (prePostEnabled = true) поверх SecurityConfig class.

И будьте осторожны при использовании .antMatchers ("/ api / getalltopics"). HasRole ("ADMIN") здесь. Я использовал вот так .antMatchers ("/ api / getalltopics"). HasAnyRole ("USER", "ADMIN") . Просто измените hasRole на hasAnyRole . Кроме того, в базе данных права пользователя должны быть записаны так: "ROLE_ADMIN" или "ROLE_USER" . Я использовал, как указано выше, и это сработало хорошо.

Если вы сохранили пароль пользователя в хешированном виде внутри базы данных, вам следует изменить фрагмент кода ниже

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

Дополнительно, Если вы создаете пользовательскую страницу входа в систему, то вы должны написать, как показано ниже, она отлично работает в моем коде

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

        http.authorizeRequests()
        .antMatchers("/resources/**").permitAll()
        .antMatchers("/").hasAnyRole("USER","ADMIN")
        .antMatchers("/add_friends").hasAnyRole( "ADMIN")
        .antMatchers("/submit_info").hasAnyRole( "ADMIN")
        .and().formLogin()
        .loginPage("/login")
        .usernameParameter("username")
        .passwordParameter("password")
        .successForwardUrl("/welcome_page")
        .permitAll()
        .and()
        .logout()
        .permitAll()
        .and()
        .exceptionHandling().accessDeniedPage("/accessDenied");

        http.csrf().disable();
    }

/ login - это файл jsp, а / welcome_page - это метод контроллера. Может быть, ваш логин и пароль не будет даже в базе данных. Проверьте это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...