首先,这是我的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();
}
}
哪个直接带我进入我的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()));
}
}
再次引导我进入我的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;
}
我只是不知道该怎么办,我很失落..
[InitialDataLoader.createRoleIfNotFound()
创建具有特权READ_PRIVILEGE
和WRITE_PRIVILEGE
的角色
[AccountService.getGrantedAuthorities()
基于特权而不是角色ADMIN来构建SimpleGrantedAuthority
对象。
这会阻止授权按预期方式工作。创建具有所需角色的SimpleGrantedAuthority
对象应在此处解决授权问题。
我认为首先您应该将@ 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()); }
此外,如果要创建自定义登录页面,则应如下所示编写,在我的代码中可以正常工作
是jsp文件,而/ welcome_page是控制器方法。也许您的登录名和密码甚至都不会进入数据库。看看。@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