当前位置: 首页 > 知识库问答 >
问题:

如何使用Spring Security性保护Spring数据Restendpoint?

茹展鹏
2023-03-14

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

我还可以调用一些RESTendpoint。我没有手动定义这些endpoint。它们是自动创建的,因为我使用的是SpringBootStarter数据rest依赖项。

REST请求的URL如下所示http://localhost:8182/api/v1/recipes.

我正试图通过邮递员获得一份食谱清单。我想得到一条类似“403禁止”之类的错误消息,因为我没有提供任何凭据。相反,我会收到登录页面的HTML代码和状态代码“200OK”。

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

user:user
password:password

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

>

@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) {
                };
            }
        };
    }
}

第二个是用户实体类:

    @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;
        }
    }

第三个片段表示扩展UserDetailsService的接口:

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();
}

第四个也是最后一个代码段是前一个接口(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授权,我必须修改什么?

共有2个答案

巫马瀚漠
2023-03-14

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

例子:。

@RestController
public class Controller {

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

添加。异常处理()。authenticationEntryPoint(新的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拒绝访问的消息。

戚俊美
2023-03-14

据我所知,你有一个RESTful API(没有用户界面),如果这是真的,你可以更新SecurityConfig#配置(HttpSecurity超文本传输协议)方法替换这个:

@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();
    }
 类似资料:
  • 本文向大家介绍如何使用SpringSecurity保护程序安全,包括了如何使用SpringSecurity保护程序安全的使用技巧和注意事项,需要的朋友参考一下 首先,引入依赖: 引入此依赖之后,你的web程序将拥有以下功能: 所有请求路径都需要认证 不需要特定的角色和权限 没有登录页面,使用HTTP基本身份认证 只有一个用户,名称为user 配置SpringSecurity springsecur

  • 我想使用keycloak作为身份验证和授权服务器来保护spring cloud数据流服务器并管理对其endpoint的访问。 我按照Spring的文档http://docs.spring.io/spring-cloud-dataflow/docs/1.7.0.rc1/reference/htmlsingle/#configuration-security-oauth2中的描述设置了scdf服务器的

  • 我正在使用Spring Data Rest向我们的React前端应用程序公开JPA存储库。我还使用Spring Security性和JWT来保护REST API。 我的问题: 如何预防这样的异常用法? 使用Spring Data REST的最佳实践是什么?

  • 问题内容: 我知道保护REST API是一个被广泛评论的话题,但是我无法创建一个符合我的标准的小型原型(并且我需要确认这些标准是现实的)。如何保护资源以及如何使用Spring安全性有很多选择,我需要弄清楚我的需求是否现实。 我的要求 基于令牌的身份验证器-用户将提供其凭据,并获得唯一且受时间限制的访问令牌。我想在自己的实现中管理令牌的创建,检查有效性和到期时间。 某些REST资源将是公开的-完全不

  • null 当前状态 请给我一些如何开始的点子。

  • 我正在开发配置了SSO/OAuth2安全性的Spring Boot应用程序。身份验证对我的rest控制器很有效,现在我需要用restendpoint保护我的Apache Camel路由。 据我所知,有几种方法可以做到这一点: 通过将身份验证处理器添加到我的路线 通过向我的路线添加策略(SpringSecurityAuthorizationPolicy) jettyendpoint的“按处理程序”选