我在项目中使用 thymeleaf-extras-springsecurity4 和弹簧安全保护。问题是我无法获得用户的额外字段(这意味着除username
之外的password
,enabled
,UserDetails
等数据库的用户信息使用<span sec:authentication="principal.something" />
。
Heres是我的简单代码:
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@EqualsAndHashCode
@Entity
@Table(name = "users", schema = "myschema")
public class UserEntity implements UserDetails {
@Id
@GeneratedValue
@Column(name = "id", nullable = false)
private int id;
@Basic
@Column(name = "username", nullable = false, unique = true, length = 64)
private String username;
@Basic
@Column(name = "password", nullable = false, columnDefinition = "TEXT")
private String password;
@Basic
@Column(name = "enabled", nullable = false, columnDefinition = "BIT")
private boolean enabled;
@Basic
@Column(name = "phone", nullable = false, length = 16)
private String phone;
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
private List<AuthorityEntity> authorities;
@Override
public boolean isAccountNonExpired() {
return enabled;
}
@Override
public boolean isAccountNonLocked() {
return enabled;
}
@Override
public boolean isCredentialsNonExpired() {
return enabled;
}
@Override
public String toString() {
return username;
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "authorities", schema = "myschema",
uniqueConstraints = @UniqueConstraint(columnNames = {"user_id", "authority"}))
public class AuthorityEntity implements GrantedAuthority {
@Id
@GeneratedValue
@Column(name = "id", nullable = false)
private int id;
@Basic
@Column(name = "authority", nullable = false, length = 24)
private String authority;
@ManyToOne
@JoinColumn(name = "user_id", referencedColumnName = "id", nullable = false)
private UserEntity user;
}
@Repository
public interface UserRepository extends JpaRepository<UserEntity, Integer> {
UserEntity findOneByUsernameAndEnabledTrue(String username);
}
@Service
public class UserService {
private UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public UserEntity loadUserByUsername(String username) {
return userRepository.findOneByUsernameAndEnabledTrue(username);
}
}
@Service
public class SecurityService implements UserDetailsService {
private UserService userService;
@Autowired
public SecurityService(UserService userService) {
this.userService = userService;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDetails user = userService.loadUserByUsername(username);
if (user == null) {
throw new UsernameNotFoundException(username);
}
return user;
}
}
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private SecurityService securityService;
@Autowired
public SecurityConfig(SecurityService securityService) {
this.securityService = securityService;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/user/login").anonymous()
.antMatchers("/**").hasAnyRole("ADMIN", "USER")
.and()
.formLogin()
.loginPage("/user/login")
.defaultSuccessUrl("/")
.and()
.logout()
.logoutUrl("/user/logout")
.logoutSuccessUrl("/")
.and()
.exceptionHandling()
.accessDeniedPage("/error/403");
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
auth.userDetailsService(securityService).passwordEncoder(passwordEncoder);
}
}
<!DOCTYPE html>
<html lang="ko"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"
layout:decorator="layout/base">
<th:block layout:fragment="content">
<h1>Main Page</h1>
<p sec:authentication="principal.username">Username</p>
<p sec:authentication="principal.phone">Phone</p>
</th:block>
在index.html
中,sec:authentication="principal.username"
按预期工作,但sec:authentication="principal.phone"
尽管我的UserDetailsService
实施存储UserEntry
实现了UserDetails
,但却没有字段phone
。
sec:authentication="principal.phone"
运作良好? (或分别为"princiapl.getPhone()"
)UserEntry
对象而不显式插入模型,例如通过每个控制器方法的mav
? AOP是否处理此问题? (附加)在应用Spring安全性的许多其他示例中,他们不会在UserDetails
(或类似的类)上实现UserEntry
,而是创建一个新{ {1}}实施中的{1}}实例,如
UserDetails
(from here)。我认为我的结构不是一个好的设计,但我不确切知道为什么。我的班级设计有什么评论吗?
如果我的问题太模糊,请告诉我,然后我会更新更具体。
答案 0 :(得分:0)
为了使用Thymeleaf
中用户数据中包含的其他字段,您必须执行以下步骤。
loadUserByUsername
,以便它返回您的自定义用户。${#authentication.getPrincipal()}
代替sec
。STEP 1
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import java.util.Collection;
// Our own implementation of the Spring Security User.
public class MyUser extends User {
// Here we add the extra fields of our users.
private String phone;
private static final long serialVersionUID = 1L;
public MyUser(String username,
String password,
Collection<GrantedAuthority> authorities,
String phone) {
super(username, password, authorities);
this.phone = phone;
}
public String getPhone() {
return realName;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
第2步
@Override
public MyUser loadUserByUsername(String userName)
throws AuthenticationException {
// Fetch the user.
UserDetails user = userService.loadUserByUsername(username);
// For each user's authority, add it into our authorities' collection.
Collection<GrantedAuthority> grantedAuthorities = new LinkedList<GrantedAuthority>();
if (user.getAuthorities().size() > 0){
for (Authority authority : user.getAuthorities()) {
// Add a new GrantedAuthority for each user's authorities.
grantedAuthorities.add(new SimpleGrantedAuthority(authority.getAuthority()));
}
}
return new MyUser(user.getUsername(), user.getPassword(), grantedAuthorities, user.getPhone());
}
第3步
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
</dependency>
第4步
<th:block th:with="auth=${#authentication.getPrincipal()}">
<p th:text="${auth ? auth.phone : 'NULL'}">Phone</p>
</th:block>