繁体   English   中英

如何使用Spring Security保护Spring Data Rest端点?

[英]How can I secure my Spring Data Rest endpoints using Spring Security?

我正在使用Spring应用程序。 在浏览器上一切都很好。 我可以使用现有用户登录,只需要提供我的用户名和密码即可。 我还可以注册一个新用户,然后使用它登录。

我也有一些我可以调用的REST端点。 我没有手动定义这些端点。 它们是自动创建的,因为我正在使用spring-boot-starter-data-rest依赖项。

REST请求的URL类似于http:// localhost:8182 / api / v1 / recipes

我正在尝试使用邮递员获得食谱列表。 我想收到一条错误消息,例如“ 403 Forbidden”或类似的消息,因为我没有提供任何凭据。 相反,我收到登录页面的HTML代码和状态代码“ 200 OK”。

这在我提供用户名和密码作为请求标头后也适用(也许我需要使用另一种方式来提供凭据)

user:user
password:password

以下列表包含一些代码片段,以显示我在项目中编写的与应用程序安全性有关的所有内容:

  1. 第一个代码段代表我项目中的SecurityConfig类:

     @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter{ @Autowired private UserService userService; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception{ auth.userDetailsService(userService).passwordEncoder(User.PASSWORD_ENCODER); } @Override public void configure(WebSecurity web) throws Exception{ web.ignoring().antMatchers("/css/**"); web.ignoring().antMatchers("/images/**"); web.ignoring().antMatchers("/js/**"); } @Override protected void configure(HttpSecurity http) throws Exception{ http.authorizeRequests() .antMatchers("/sign-up").permitAll() .anyRequest() .hasRole("USER") .and() .formLogin() .loginPage("/login") .permitAll() .successHandler(loginSuccessHandler()) .failureHandler(loginFailureHandler()) .and() .logout() .permitAll() .logoutSuccessUrl("/login") .and() .csrf().disable(); } public AuthenticationSuccessHandler loginSuccessHandler(){ return (request, response, authentication) ->{ response.sendRedirect("/recipes/"); }; } public AuthenticationFailureHandler loginFailureHandler(){ return (request, response, exception) ->{ request.getSession().setAttribute("flash", new FlashMessage("Incorrect username and/or password. Try again.", FlashMessage.Status.FAILURE)); response.sendRedirect("/login"); }; } @Bean public EvaluationContextExtension securityExtension(){ return new EvaluationContextExtensionSupport() { @Override public String getExtensionId() { return "security"; } @Override public Object getRootObject(){ Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); return new SecurityExpressionRoot(authentication) { }; } }; } } 
  2. 第二个是User实体类:

      @Entity public class User implements UserDetails{ public static final PasswordEncoder PASSWORD_ENCODER = new BCryptPasswordEncoder(); @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotNull @Column(unique = true) @Size(min = 2, max = 20) private String username; @NotNull @Column(length = 100) @JsonIgnore private String password; @NotNull @Column(length = 100) @JsonIgnore private String matchingPassword; @Column(nullable = false) private boolean enabled; @OneToOne @JoinColumn(name = "role_id") @JsonIgnore private Role role; @ManyToMany(targetEntity = Recipe.class, fetch = FetchType.EAGER) @JoinTable(name = "users_favorite_recipes", joinColumns = @JoinColumn(name="user_id"), inverseJoinColumns = @JoinColumn(name = "recipe_id")) private List<Recipe> favoritedRecipes = new ArrayList<>(); @JsonIgnore @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) private List<Recipe> ownedRecipes = new ArrayList<>(); //constructor ... //getters and setters ... public void encryptPasswords(){ password = PASSWORD_ENCODER.encode(password); matchingPassword = PASSWORD_ENCODER.encode(matchingPassword); } @Override public Collection<? extends GrantedAuthority> getAuthorities() { List<GrantedAuthority> authorities = new ArrayList<>(); authorities.add(new SimpleGrantedAuthority(role.getName())); return authorities; } @Override public String getPassword() { return password; } @Override public String getUsername() { return username; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return enabled; } } 
  3. 第三个代码片段表示扩展UserDetailsS​​ervice的接口:

     public interface UserService extends UserDetailsService{ UserDetails loadUserByUsername(String username); User findByUsername(String username); User registerNewUser(String username, boolean enabled, String password, String matchingPassword); void save(User user); List<User> findAll(); } 
  4. 第四个也是最后一个代码片段是先前接口(UserService)的实现:

     @Component @ComponentScan public class UserServiceImpl implements UserService{ @Autowired private UserDao userDao; @Autowired private RoleDao roleDao; @Override public User findByUsername(String username) { User user = userDao.findByUsername(username); Hibernate.initialize(user.getFavoritedRecipes()); return user; } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException{ User user = userDao.findByUsername(username); if(user == null){ throw new UsernameNotFoundException( username + " was not found" ); } return user; } @Override public void save(User user) { userDao.save(user); } @Override public User registerNewUser(String username, boolean enabled, String password, String matchingPassword) { return userDao.save(new User(username, enabled, password, matchingPassword)); } @Override public List<User> findAll() { return userDao.findAll(); } } 

为了获得功能性的REST API授权,在这种情况下我必须修改什么?

据我了解,您有一个RESTful API (没有UI ),如果是这样,则可以更新SecurityConfigconfigure(HttpSecurity http)方法,将其替换为:

@Override
protected void configure(HttpSecurity http) throws Exception{
    http.authorizeRequests()
            .antMatchers("/sign-up").permitAll()
            .anyRequest()
            .hasRole("USER")
            .and()
            .formLogin()
            .loginPage("/login")
            .permitAll()
            .successHandler(loginSuccessHandler())
            .failureHandler(loginFailureHandler())
            .and()
            .logout()
            .permitAll()
            .logoutSuccessUrl("/login")
            .and()
            .csrf().disable();
}

这样 :

@Override
    protected void configure(HttpSecurity http) throws Exception {
            http
                .cors()
                .and()
                .csrf()
                .disable()
                .exceptionHandling()
                .authenticationEntryPoint((request, response, exc) ->
                        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "You are not authorized to access this resource."))
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                // Array of String that contain's all endpoints you want secure
                .antMatchers(ENDPOINTS_TO_SECURE).access("hasAnyRole('ROLE_USER')")
                // Array of String that contain's all endpoints you want to permit
                .antMatchers(WHITE_LIST).permitAll()
                .anyRequest()
                .authenticated();
        // disable page caching
        http.headers().cacheControl();
    }

您需要配置自己的身份验证入口点,要获取403消息,可以使用Http403ForbiddenEntryPoint。

例:。

@RestController
public class Controller {

    @GetMapping("/test")
    public String test() {
        return "test";
    }
}

添加.exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint())

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http.authorizeRequests()
                .antMatchers("/sign-up").permitAll()
                .anyRequest()
                .hasRole("USER")
                .and()
                .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
                .logout()
                .permitAll()
                .logoutSuccessUrl("/login")
                .and()
                .csrf().disable()
                .exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint());
    }
}

现在,当我尝试访问http://localhost:8080/test ,我收到403 Access Denied消息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM