我正在尝试在查询中使用Spring Security表达式。如36. Security Expressions within @Query所示
public interface BookRepository extends JpaRepository<Book, Long> {
@PreAuthorize("hasAuthority('AUTHOR')")
@Query("select b from Book b where b.author.id = ?#{ principal?.id }")
Page<Book> findAllOwned(Pageable p);
}
而且我得到下面的错误。
2018-01-28 01:50:10.672 ERROR 12985 --- [nio-8443-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'aid' cannot be found on object of type 'java.lang.String' - maybe not public?] with root cause
org.springframework.expression.spel.SpelEvaluationException:
EL1008E:
Property or field 'id' cannot be found on object of type 'java.lang.String' - maybe not public?
请帮助解决问题。我究竟做错了什么?
我在下面列出了我认为必要且与该问题相关的课程。
我已经定义
@Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
和用户详细服务
@Component
public class AppUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User user = userRepository.findByUsername(s);
if (user == null) {
throw new UsernameNotFoundException(String.format("The username %s doesn't exist", s));
}
List<GrantedAuthority> authorities = new ArrayList<>();
user.getRoles()
.forEach(role -> {
authorities.add(new SimpleGrantedAuthority(role.getRoleName()));
});
return new PrincipalUser(user.getId(), user.getUsername(), user.getPassword(), authorities);
}
}
自定义主要用户
public class PrincipalUser extends User {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
private Long id;
public PrincipalUser(Long id, String username, String password, Collection<? extends GrantedAuthority> authorities) {
super(username, password, authorities);
this.id = id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
图书实体
@Entity
@EntityListeners(AuditingEntityListener.class)
@Table(name = "book")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name", unique=true)
private String name;
@Column(name = "shortcode")
private String shortcode;
@ManyToOne
@JoinColumn(name="author_user_id")
private User author;
@CreatedDate
@Column(name = "created_date", columnDefinition="DATETIME")
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate;
@CreatedBy
@Column(name="created_by")
private String createdBy;
@LastModifiedDate
@Column(name = "last_modified_date", columnDefinition="DATETIME")
@Temporal(TemporalType.TIMESTAMP)
private Date lastModifiedDate;
@LastModifiedBy
@Column(name="last_modified_by")
private String lastModifiedBy;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getShortcode() {
return shortcode;
}
public void setShortcode(String shortcode) {
this.shortcode = shortcode;
}
public User getAuthor() {
return author;
}
public void setAuthor(User author) {
this.author = author;
}
public Date getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public Date getLastModifiedDate() {
return lastModifiedDate;
}
public void setLastModifiedDate(Date lastModifiedDate) {
this.lastModifiedDate = lastModifiedDate;
}
public String getLastModifiedBy() {
return lastModifiedBy;
}
public void setLastModifiedBy(String lastModifiedBy) {
this.lastModifiedBy = lastModifiedBy;
}
}
用户实体
@Entity
@EntityListeners(AuditingEntityListener.class)
@Table(name = "app_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "username", unique=true)
private String username;
@Column(name = "password")
@JsonDeserialize(using = BCryptPasswordDeserializer.class )
private String password;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "email")
private String email;
@Column(name = "is_active")
private boolean isActive;
@CreatedDate
@Column(name = "created_date", columnDefinition="DATETIME")
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate;
@CreatedBy
@Column(name="created_by")
private String createdBy;
@LastModifiedDate
@Column(name = "last_modified_date", columnDefinition="DATETIME")
@Temporal(TemporalType.TIMESTAMP)
private Date lastModifiedDate;
@LastModifiedBy
@Column(name="last_modified_by")
private String lastModifiedBy;
@OneToMany(mappedBy="author")
private List<Book> authoredBooks;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "user_role", joinColumns
= @JoinColumn(name = "user_id",
referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "role_id",
referencedColumnName = "id"))
private List<Role> roles;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
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 getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public boolean isActive() {
return isActive;
}
public void setActive(boolean isActive) {
this.isActive = isActive;
}
public Date getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public Date getLastModifiedDate() {
return lastModifiedDate;
}
public void setLastModifiedDate(Date lastModifiedDate) {
this.lastModifiedDate = lastModifiedDate;
}
public String getLastModifiedBy() {
return lastModifiedBy;
}
public void setLastModifiedBy(String lastModifiedBy) {
this.lastModifiedBy = lastModifiedBy;
}
public List<Book> getAuthoredBooks() {
return authoredBooks;
}
public void setAuthoredBooks(List<Book> authoredBooks) {
this.authoredBooks = authoredBooks;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
}
扩展的SecurityEvaluationContextExtension
class SecurityEvaluationContextExtension extends EvaluationContextExtensionSupport {
@Override
public String getExtensionId() {
return "security";
}
@Override
public SecurityExpressionRoot getRootObject() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return new SecurityExpressionRoot(authentication) {};
}
}
堆栈跟踪的前几行:
ERROR 18238 --- [nio-8443-exec-9] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'id' cannot be found on object of type 'java.lang.String' - maybe not public?] with root cause
org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'id' cannot be found on object of type 'java.lang.String' - maybe not public?
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:226) ~[spring-expression-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:94) ~[spring-expression-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.expression.spel.ast.PropertyOrFieldReference.access$000(PropertyOrFieldReference.java:46) ~[spring-expression-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.expression.spel.ast.PropertyOrFieldReference$AccessorLValue.getValue(PropertyOrFieldReference.java:379) ~[spring-expression-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:88) ~[spring-expression-4.3.13.RELEASE.jar:4.3.13.RELEASE]
Full Stack Trace ...
最佳答案
似乎有多余的?在这个例子中。尝试:
@Query("select b from Book b where b.author.id = ?#{principal.id}")