如何保护 RepositoryRestController
How to secure RepositoryRestController
假设我有 2 个实体:
@Entity
public class Post {
@NotEmpty
private String title;
@NotEmpty
@Lob
private String html;
@NotEmpty
@Lob
private String text;
@ManyToOne
private Topic topic;
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(name = "content_media", joinColumns = {@JoinColumn(name = "content_id")}, inverseJoinColumns = {@JoinColumn(name = "media_id")})
private Set<Media> medias = new HashSet<>();
@CreatedBy
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn
private User createdBy;
@LastModifiedBy
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn
private User lastModifiedBy;
...
}
@Entity
public class Media {
@NotEmpty
private String localPath;
@NotEmpty
private String fileName;
private long fileLength;
private String fileType;
private int focusPointX;
private int focusPointY;
...
}
我使用以下方式公开它们:
@RepositoryRestController
public interface MediaRepository extends JpaRepository<Media, Long> {
}
@RepositoryRestController
public interface PostRepository extends JpaRepository<Post, Long> {
}
我希望这些控制器是安全的。让我自己解释一下。
- 如果登录用户没有 ROLE_ADMIN,媒体应该只
可通过 posts 和 /medias/ 访问 return 403 或 404
- 只有 ROLE_USER 的用户才能创建 posts
- 只有创建了 post 或拥有 ROLE_ADMIN 的用户才能更新 post。
- 只有拥有 ROLE_ADMIN 的用户才能删除 post
有没有办法使用 RepositoryRestController 和 Spring 安全性或 RepositoryRestController 仅用于 public 资源,我应该使用 RestController 自己编写服务层?
是的,您可以直接将 Spring 安全与 Spring 数据 REST 结合使用。您需要使用 Spring 安全配置来定义路由的安全性,如下所示:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().
antMatchers(HttpMethod.POST, "/posts").hasRole("USER").
antMatchers(HttpMethod.DELETE, "/posts/**").hasRole("ADMIN").and().
csrf().disable();
}
}
存储库方法将使用 Spring 安全注释进行保护。例如
@RepositoryRestController
public interface PostRepository extends JpaRepository<Post, Long> {
@Override
@PreAuthorize("hasRole('ROLE_ADMIN')")
void delete(Long aLong);
}
上面的代码只是一个指针。您可以根据需要自定义它。 Here is the link to Spring Data examples repository.
更新
要处理由创建的用户或 ADMIN_ROLE 中的任何用户对 post 的更新,您需要创建一个控制器 class 并定义一个方法来处理更新
@RequestMapping(method={RequestMethod.PUT}, value={"posts/{id}"})
public void updatePost(@PathVariable("id") Long id, HttpServletRequest request)
{
//Fetch the authenticated user name
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
Object principal = authentication.getPrincipal();
if (principal instanceof UserDetails) {
username = ((UserDetails) principal).getUsername();
}
// Make a database call to verify if the user is owner of the post
Post post = postRepository.getPostByUserName(String username, Long postId);
if (post == null && !request.isUserInRole("ADMIN");) {
//return 403 error code
}
//proceed with the update
}
假设我有 2 个实体:
@Entity
public class Post {
@NotEmpty
private String title;
@NotEmpty
@Lob
private String html;
@NotEmpty
@Lob
private String text;
@ManyToOne
private Topic topic;
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(name = "content_media", joinColumns = {@JoinColumn(name = "content_id")}, inverseJoinColumns = {@JoinColumn(name = "media_id")})
private Set<Media> medias = new HashSet<>();
@CreatedBy
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn
private User createdBy;
@LastModifiedBy
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn
private User lastModifiedBy;
...
}
@Entity
public class Media {
@NotEmpty
private String localPath;
@NotEmpty
private String fileName;
private long fileLength;
private String fileType;
private int focusPointX;
private int focusPointY;
...
}
我使用以下方式公开它们:
@RepositoryRestController
public interface MediaRepository extends JpaRepository<Media, Long> {
}
@RepositoryRestController
public interface PostRepository extends JpaRepository<Post, Long> {
}
我希望这些控制器是安全的。让我自己解释一下。
- 如果登录用户没有 ROLE_ADMIN,媒体应该只 可通过 posts 和 /medias/ 访问 return 403 或 404
- 只有 ROLE_USER 的用户才能创建 posts
- 只有创建了 post 或拥有 ROLE_ADMIN 的用户才能更新 post。
- 只有拥有 ROLE_ADMIN 的用户才能删除 post
有没有办法使用 RepositoryRestController 和 Spring 安全性或 RepositoryRestController 仅用于 public 资源,我应该使用 RestController 自己编写服务层?
是的,您可以直接将 Spring 安全与 Spring 数据 REST 结合使用。您需要使用 Spring 安全配置来定义路由的安全性,如下所示:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().
antMatchers(HttpMethod.POST, "/posts").hasRole("USER").
antMatchers(HttpMethod.DELETE, "/posts/**").hasRole("ADMIN").and().
csrf().disable();
}
}
存储库方法将使用 Spring 安全注释进行保护。例如
@RepositoryRestController
public interface PostRepository extends JpaRepository<Post, Long> {
@Override
@PreAuthorize("hasRole('ROLE_ADMIN')")
void delete(Long aLong);
}
上面的代码只是一个指针。您可以根据需要自定义它。 Here is the link to Spring Data examples repository.
更新 要处理由创建的用户或 ADMIN_ROLE 中的任何用户对 post 的更新,您需要创建一个控制器 class 并定义一个方法来处理更新
@RequestMapping(method={RequestMethod.PUT}, value={"posts/{id}"})
public void updatePost(@PathVariable("id") Long id, HttpServletRequest request)
{
//Fetch the authenticated user name
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
Object principal = authentication.getPrincipal();
if (principal instanceof UserDetails) {
username = ((UserDetails) principal).getUsername();
}
// Make a database call to verify if the user is owner of the post
Post post = postRepository.getPostByUserName(String username, Long postId);
if (post == null && !request.isUserInRole("ADMIN");) {
//return 403 error code
}
//proceed with the update
}