【发布时间】:2019-06-19 09:17:07
【问题描述】:
我正在使用 Spring 应用程序。在浏览器上一切正常。我可以使用现有用户登录,只需提供我的用户名和密码。我也可以用新用户注册,然后用它登录。
我还可以调用一些可用的 REST 端点。我没有手动定义这些端点。它们是自动创建的,因为我使用的是 spring-boot-starter-data-rest 依赖项。
REST 请求的 URL 类似于 http://localhost:8182/api/v1/recipes。
我正在尝试使用 Postman 获取食谱列表。我想收到类似“403 Forbidden”之类的错误消息,或者类似的东西,因为我没有提供任何凭据。相反,我收到了登录页面的 HTML 代码,以及“200 OK”的状态代码。
这也适用于我提供用户名和密码作为请求标头之后(也许我需要使用另一种方式来提供凭据)
user:user
password:password
以下列表包含一些 sn-ps 代码,以显示我在项目中编写的有关应用程序安全位的所有内容:
-
代码的第一个 sn-p 代表我项目中的 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; } } -
第三个 sn-p 代表一个接口,扩展了 用户详情服务:
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(); } -
第四个也是最后一个sn-p是前一个的实现 接口(用户服务):
@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 授权?
【问题讨论】:
标签: java spring spring-boot spring-security spring-data-rest