Spring Security用户没有角色

问题描述 投票:0回答:2

首先,这是我的Spring Security配置

@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();
    }
}

哪个直接带我进入我的AccountDetailsS​​ervice

@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()));
    }
}

再次引导我进入我的accountService

@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角色后,稍后我尝试检查该用户是否具有该角色,但总是返回false。如果我尝试与该用户向服务器发出一些请求,则始终会收到403 Forbidden。我在这里错了吗?

在我的班上,我设置了测试用户,这是我用来尝试登录的用户

@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;
    }

我只是不知道该怎么办,我很失落..

spring spring-security
2个回答
1
投票

[InitialDataLoader.createRoleIfNotFound()创建具有特权READ_PRIVILEGEWRITE_PRIVILEGE的角色

[AccountService.getGrantedAuthorities()基于特权而不是角色ADMIN来构建SimpleGrantedAuthority对象。

这会阻止授权按预期方式工作。创建具有所需角色的SimpleGrantedAuthority对象应在此处解决授权问题。


1
投票

我认为首先您应该将@ EnableGlobalMethodSecurity(prePostEnabled = true)放在SecurityConfig类的顶部。

并且在使用时要小心.. antMatchers(“ / api / getalltopics”)。hasRole(“ ADMIN”)此处。我曾经这样.. antMatchers(“ / api / getalltopics”)。hasAnyRole(“ USER”,“ ADMIN”)] >>。只需用hasAnyRole更改hasRole。另外,在数据库中,用户的权限应这样写:“ 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是控制器方法。也许您的登录名和密码甚至都不会进入数据库。看看。
© www.soinside.com 2019 - 2024. All rights reserved.