![](/img/trans.png)
[英]How to insert data under secure rest endpoints by spring security using MYSQL
[英]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
以下列表包含一些代碼片段,以顯示我在項目中編寫的與應用程序安全性有關的所有內容:
第一個代碼段代表我項目中的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) { }; } }; } }
第二個是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; } }
第三個代碼片段表示擴展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授權,在這種情況下我必須修改什么?
據我了解,您有一個RESTful API (沒有UI ),如果是這樣,則可以更新SecurityConfig # configure(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.