Roles in Spring Boot application not working when database auth is used but works if in memory is used

huangapple go评论116阅读模式
英文:

Roles in Spring Boot application not working when database auth is used but works if in memory is used

问题

我正在尝试在我的Spring Boot应用程序中设置安全角色

如果我使用内存中的用户角色是有效的我的代码如下所示

```Java
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		
    // 为内存中的身份验证添加用户
	UserBuilder users = User.withDefaultPasswordEncoder();
		
	auth.inMemoryAuthentication()
	    .withUser(users.username("paul").password("test123").roles("MEMBER", "ADMIN"))
	    .withUser(users.username("sandra").password("test123").roles("MEMBER", "ADMIN"))
	    .withUser(users.username("matthew").password("test123").roles("MEMBER"));
}

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

	http.authorizeRequests()
		.antMatchers("/users/list").hasAnyRole("MEMBER", "ADMIN")
		.antMatchers("/events/list").hasAnyRole("MEMBER", "ADMIN")
		.antMatchers("/events/showFormForAdd").hasRole("ADMIN")
		.antMatchers("/events/listEventAttendeeDetails*").hasRole("ADMIN")
		.antMatchers("/resources/**").permitAll()
		.and()
		.formLogin()
				.loginPage("/showMyLoginPage")
				.loginProcessingUrl("/authenticateTheUser")
				.permitAll();
}

如果我在configure()中使用数据库身份验证,则用户未被授权访问任何页面。我的数据库方法如下所示:

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

由于内存中的角色有效而数据库中无效,我认为configure(HttpSecurity http)应该正常工作。我怀疑在获取角色方面可能存在问题。我的User和Authority(角色)模型如下:

@Entity
@Table(name="users")
public class User {
	// ...
}

@Entity
@Table(name="authorities")
public class Authority {
	// ...
}

这是我用于身份验证的服务:

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    // ...
}

权限被插入到数据库中,如下所示:

INSERT INTO `authorities` 
VALUES 
('john','ROLE_MEMBER'),
('mary','ROLE_MEMBER'),
('mary','ROLE_MANAGER'),
('susan','ROLE_MEMBER'),
('susan','ROLE_ADMIN');

我在UserDetailsServiceImpl周围添加了一些日志。正如您所见,没有授予任何权限。

2020-10-21 17:02:17.612  INFO 20363 --- [nio-8080-exec-4] c.p.clubmanager.aspect.LoggingAspect     : =====> in @Before: Calling method: UserDetailsServiceImpl.loadUserByUsername(..)
2020-10-21 17:02:17.613  INFO 20363 --- [nio-8080-exec-4] c.p.clubmanager.aspect.LoggingAspect     : =====> argument: Paul_carron@hotmail.com
2020-10-21 17:02:17.619  INFO 20363 --- [nio-8080-exec-4] c.p.clubmanager.aspect.LoggingAspect     : =====> in @AfterReturning: from method: UserDetailsServiceImpl.loadUserByUsername(..)
2020-10-21 17:02:17.619  INFO 20363 --- [nio-8080-exec-4] c.p.clubmanager.aspect.LoggingAspect     : =====> result: org.springframework.security.core.userdetails.User@eefb770b: Username: Paul_carron@hotmail.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; **Not granted any authorities**

我是否做错了什么,或者在获取角色方面是否遗漏了什么?


<details>
<summary>英文:</summary>
I&#39;m trying to set security roles in my Spring Boot application.
If I use in memory users the roles work. My code looks as folows:
```Java
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// add users for in memory authentication
UserBuilder users = User.withDefaultPasswordEncoder();
auth.inMemoryAuthentication()
.withUser(users.username(&quot;paul&quot;).password(&quot;test123&quot;).roles(&quot;MEMBER&quot;, &quot;ADMIN&quot;))
.withUser(users.username(&quot;sandra&quot;).password(&quot;test123&quot;).roles(&quot;MEMBER&quot;, &quot;ADMIN&quot;))
.withUser(users.username(&quot;matthew&quot;).password(&quot;test123&quot;).roles(&quot;MEMBER&quot;));
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(&quot;/users/list&quot;).hasAnyRole(&quot;MEMBER&quot;, &quot;ADMIN&quot;)
.antMatchers(&quot;/events/list&quot;).hasAnyRole(&quot;MEMBER&quot;, &quot;ADMIN&quot;)
.antMatchers(&quot;/events/showFormForAdd&quot;).hasRole(&quot;ADMIN&quot;)
.antMatchers(&quot;/events/listEventAttendeeDetails*&quot;).hasRole(&quot;ADMIN&quot;)
.antMatchers(&quot;/resources/**&quot;).permitAll()
.and()
.formLogin()
.loginPage(&quot;/showMyLoginPage&quot;)
.loginProcessingUrl(&quot;/authenticateTheUser&quot;)
.permitAll();
}

If I use database authentication for configure() the user is not authorised to access any pages. My database method looks like this:

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

As The roles work for in memory and not database I thing the configure(HttpSecurity http) must work fine. I suspect there is some issue getting my roles. My User and Authority(roles) models are as follows:

@Entity
@Table(name=&quot;users&quot;)
public class User {
	
	public static final PasswordEncoder PASSWORD_ENCODER = new BCryptPasswordEncoder();
	
	@OneToMany(mappedBy=&quot;user&quot;,
			cascade={CascadeType.PERSIST, CascadeType.MERGE,
					CascadeType.DETACH, CascadeType.REFRESH,
					CascadeType.REMOVE})
	private List&lt;Authority&gt; authorities;

	// define fields
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name=&quot;id&quot;)
	private int id;

	@Column(name=&quot;first_name&quot;)
	private String firstName;

	@Column(name=&quot;last_name&quot;)
	private String lastName;
	
	@Column(name=&quot;gender&quot;)
	private String gender;
	
	@DateTimeFormat(pattern=&quot;yyyy-MM-dd&quot;)
	@Column(name=&quot;birth_date&quot;)
	private LocalDate birthDate;
	
	@Column(name=&quot;address_line1&quot;)
	private String addressLine1;
	
	@Column(name=&quot;address_line2&quot;)
	private String addressLine2;
	
	@Column(name=&quot;town&quot;)
	private String town;
	
	@Column(name=&quot;county&quot;)
	private String county;
	
	@Column(name=&quot;country&quot;)
	private String country;
	
	@Column(name=&quot;postcode&quot;)
	private String postcode;
	
	@Column(name=&quot;email&quot;)
	private String email;
	
	@Column(name=&quot;phone&quot;)
	private String phone;
	
	@Column(name=&quot;mobile&quot;)
	private String mobile;
	
	@Column(name=&quot;password&quot;)
	private @JsonIgnore String password;
	
	@Column(name=&quot;enabled&quot;)
	private int enabled;

	// define constructors
	public User() {
		
	}
	
	public User(List&lt;Authority&gt; authorities, int id, String firstName, String lastName, String gender, LocalDate birthDate,
		String addressLine1, String addressLine2, String town, String county, String country, String postcode,
		String email, String phone, String mobile, String password, int enabled) {
		this.authorities = authorities;
		this.id = id;
		this.firstName = firstName;
		this.lastName = lastName;
		this.gender = gender;
		this.birthDate = birthDate;
		this.addressLine1 = addressLine1;
		this.addressLine2 = addressLine2;
		this.town = town;
		this.county = county;
		this.country = country;
		this.postcode = postcode;
		this.email = email;
		this.phone = phone;
		this.mobile = mobile;
		this.password = password;
		this.enabled = enabled;
	}
	
	public List&lt;Authority&gt; getAuthorities() {
		return authorities;
	}

	public void setAuthorities(List&lt;Authority&gt; authorities) {
		this.authorities = authorities;
	}
	
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}

	public LocalDate getBirthDate() {
		return birthDate;
	}

	public void setBirthDate(LocalDate birthDate) {
		this.birthDate = birthDate;
	}

	public String getAddressLine1() {
		return addressLine1;
	}

	public void setAddressLine1(String addressLine1) {
		this.addressLine1 = addressLine1;
	}

	public String getAddressLine2() {
		return addressLine2;
	}

	public void setAddressLine2(String addressLine2) {
		this.addressLine2 = addressLine2;
	}

	public String getTown() {
		return town;
	}

	public void setTown(String town) {
		this.town = town;
	}

	public String getCounty() {
		return county;
	}

	public void setCounty(String county) {
		this.county = county;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

	public String getPostcode() {
		return postcode;
	}

	public void setPostcode(String postcode) {
		this.postcode = postcode;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getMobile() {
		return mobile;
	}

	public void setMobile(String mobile) {
		this.mobile = mobile;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = PASSWORD_ENCODER.encode(password);
	}

	public int getEnabled() {
		return enabled;
	}

	public void setEnabled(int enabled) {
		this.enabled = enabled;
	}
	
}


@Entity
@Table(name=&quot;authorities&quot;)
public class Authority {
	
	@ManyToOne(cascade= {CascadeType.PERSIST, CascadeType.MERGE,
			CascadeType.DETACH, CascadeType.REFRESH})
	@JoinColumn(name=&quot;email&quot;)
	private User user;
	
	@Id
	@Column(name=&quot;id&quot;)
	private String email;

	@Column(name=&quot;authority&quot;)
	private String authority;
	
	public Authority() {
		
	}

	public Authority(User user, String email, String authority) {
		this.user = user;
		this.email = email;
		this.authority = authority;
	}

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getAuthority() {
		return authority;
	}

	public void setAuthority(String authority) {
		this.authority = authority;
	}

}

This is the service I'm using to authenticate:

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    
    @Autowired private UserRepository userRepository = null;

    @Override
    @Transactional(readOnly = true)
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        org.springframework.security.core.userdetails.User user = null;

        try {
            Optional&lt;User&gt; optional = userRepository.findByEmail(username);
            HashSet&lt;GrantedAuthority&gt; set = new HashSet&lt;&gt;();
            /*
             * Add SimpleGrantedAuthority to set as appropriate
             */
            user = new org.springframework.security.core.userdetails.User(username, optional.get().getPassword(), set);
        } catch (UsernameNotFoundException exception) {
            throw exception;
        } catch (Exception exception) {
            throw new UsernameNotFoundException(username);
        }

        return user;
    }
}

The Authorities are inserted into the DB as follows:

INSERT INTO `authorities` 
VALUES 
(&#39;john&#39;,&#39;ROLE_MEMBER&#39;),
(&#39;mary&#39;,&#39;ROLE_MEMBER&#39;),
(&#39;mary&#39;,&#39;ROLE_MANAGER&#39;),
(&#39;susan&#39;,&#39;ROLE_MEMBER&#39;),
(&#39;susan&#39;,&#39;ROLE_ADMIN&#39;);

I put some logging around UserDetailsServiceImpl. As you can see, no authorities are granted.

2020-10-21 17:02:17.612  INFO 20363 --- [nio-8080-exec-4] c.p.clubmanager.aspect.LoggingAspect     : =====&gt; in @Before: Calling method: UserDetailsServiceImpl.loadUserByUsername(..)
2020-10-21 17:02:17.613  INFO 20363 --- [nio-8080-exec-4] c.p.clubmanager.aspect.LoggingAspect     : =====&gt; argument: Paul_carron@hotmail.com
2020-10-21 17:02:17.619  INFO 20363 --- [nio-8080-exec-4] c.p.clubmanager.aspect.LoggingAspect     : =====&gt; in @AfterReturning: from method: UserDetailsServiceImpl.loadUserByUsername(..)
2020-10-21 17:02:17.619  INFO 20363 --- [nio-8080-exec-4] c.p.clubmanager.aspect.LoggingAspect     : =====&gt; result: org.springframework.security.core.userdetails.User@eefb770b: Username: Paul_carron@hotmail.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; **Not granted any authorities**

Is there anything I've done wrong, or may be missing in terms of getting my roles?

答案1

得分: 2

UserDetailsServiceImpl 中,看起来你只是传递了一个空的 new HashSet&lt;&gt;() 来设置 Roles/Authority。你可以尝试这样做:

try {
    Optional&lt;User&gt; optional = userRepository.findByEmail(username);
    List&lt;SimpleGrantedAuthority&gt; authorities = new ArrayList&lt;&gt;();

    if (optional.isPresent()) {
        authorities = optional.get().getAuthorities().stream()
            .map(role -&gt; new SimpleGrantedAuthority("ROLE_" + role.getName()))
            .collect(Collectors.toList());
    }
    user = new org.springframework.security.core.userdetails.User(username, optional.get().getPassword(), authorities);
} catch (UsernameNotFoundException exception) {
    throw exception;
} catch (Exception exception) {
    throw new UsernameNotFoundException(username);
}
英文:

In UserDetailsServiceImpl it seems that you are setting Roles/Authority passing only new HashSet&lt;&gt;(). You can try this:

try {
Optional&lt;User&gt; optional = userRepository.findByEmail(username);
List&lt;SimpleGrantedAuthority&gt; authorities =  set = new ArrayList&lt;&gt;();
if(optional.isPresent()) {
authorities = optional.get().getAuthorities().stream()
.map(role -&gt; new SimpleGrantedAuthority(&quot;ROLE_&quot; + role.getName()))
.collect(Collectors.toList()))
}
user = new org.springframework.security.core.userdetails.User(username, optional.get().getPassword(), authorities);
} catch (UsernameNotFoundException exception) {
throw exception;
} catch (Exception exception) {
throw new UsernameNotFoundException(username);
}

huangapple
  • 本文由 发表于 2020年10月22日 00:15:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/64467707.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定