我似乎无法正确获取我的安全配置。无论我在使用hasRole
时做什么,我的端点总是返回403。
除非我在antMatchers
和.requestMatchers()
下复制.authorizeRequests()
,否则我无法继续工作。我在这里显然遗漏了一些东西。
基本上我希望一切都要求身份验证,但是如果用户是某些组的成员(现在只是管理员),只有一些端点可以访问。
我的安全配置如下。 hasRole
旁边的所有内容都有效。
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.requestMatchers()
.antMatchers(HttpMethod.GET, "/v2/api-docs", "/swagger-resources/**", "/swagger-ui.html")
.antMatchers(HttpMethod.GET, "/users")
.and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/v2/api-docs", "/swagger-resources/**", "/swagger-ui.html").permitAll()
.antMatchers(HttpMethod.GET, "/users").hasRole("ADMIN")
.anyRequest().authenticated();
}
// Inspiration: https://spring.io/blog/2015/06/08/cors-support-in-spring-framework#comment-2416096114
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**");
}
}
我的身份验证配置如下
@Configuration
@EnableResourceServer
public class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter {
private final UserDetailsService userService;
private final PasswordEncoder passwordEncoder;
public AuthenticationConfiguration(UserDetailsService userService, PasswordEncoder passwordEncoder) {
this.userService = userService;
this.passwordEncoder = passwordEncoder;
}
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userService)
.passwordEncoder(passwordEncoder);
}
}
我的AuthorizationServerConfiguration如下
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
public AuthorizationServerConfiguration(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("html5")
.secret("password")
.authorizedGrantTypes("password")
.scopes("openid");
}
}
我很乐意发布我的用户服务和其他内容。但是一切似乎都在hasRole
旁边工作,Principal
加载了正确的权限(角色)。但如果我要发布更多代码,请告诉我。
可以找到整个源代码here。
答案 0 :(得分:0)
根据我对该问题的评论,我将提供我用于测试的示例OAuth2配置类。我总是使用两个不同的webapp,因为我想要在auth服务器和资源服务器之间划清界限(因为它使配置变得更加困难......),所以我的示例在单个webapp中使用时可能需要进行一些调整。
auth服务器的配置:
@EnableAuthorizationServer
@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
private TokenStore tokenStore;
private DataSource dataSource;
@Autowired
public OAuth2Config(TokenStore tokenStore,
DataSource dataSource) {
this.tokenStore = tokenStore;
this.dataSource = dataSource;
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore);
}
@Configuration
public static class TokenStoreConfiguration {
@Bean
public TokenStore tokenStore(DataSource dataSource) {
return new JdbcTokenStore(dataSource);
}
}
}
资源服务器的配置:
@EnableResourceServer
@Configuration
public class OAuth2Config extends ResourceServerConfigurerAdapter {
public static final String PROPERTY_RESOURCE_ID = "com.test.oauth.resourceId";
private Environment environment;
private TokenStore tokenStore;
@Autowired
public OAuth2Config(Environment environment,
TokenStore tokenStore) {
this.environment = environment;
this.tokenStore = tokenStore;
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore)
.resourceId(environment.getProperty(PROPERTY_RESOURCE_ID))
.stateless(true);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/demo")
.access("hasRole('DEMO')")
.anyRequest().denyAll()
.and()
.formLogin().disable()
.logout().disable()
.jee().disable()
.x509().disable();
}
@Configuration
public static class TokenStoreConfiguration {
@Bean
public TokenStore tokenStore(DataSource dataSource) {
return new JdbcTokenStore(dataSource);
}
}
}
显然,这要求您配置DataSource
bean。此实现使用spring security OAuth2提供的默认表(它们远非理想,但可以根据需要进行自定义)。
您可能需要根据自己的情况调整一些事项(如果人们可能希望将它与JDBC一起使用,我将保留我提供的类作为参考):
TokenStore
类型的bean并使用InMemoryTokenStore
代替JdbcTokenStore
inMemory()
实施替换客户端的配置,并删除对我自动连接DataSource
的所有引用requestMatchers()
之前提供authorizeRequests()
。根据处理配置的顺序和添加的过滤器链,可能需要这样才能在不需要OAuth令牌的情况下到达oauth端点。编辑:通过ritesh.garg查看答案我认为我提供的内容可能无法解决您的问题,但可能有助于确定在何处以及如何开始配置Spring Security OAuth2(当我第一次找到它时这样做很难做到,因为当时我找不到任何明确的例子,虽然这可能已经改变了)
答案 1 :(得分:0)
我遇到了同样的问题,我只是忘记从 UserDetails(SpringSecurity 类)实现 getAuthorities() 方法。看看我的实体:
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@Entity
@Table(name = "tb_user")
public class User implements UserDetails, Serializable {
private static final long serialVersionUID = -6519124777839966091L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
@Column(unique = true)
private String email;
private String password;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "tb_user_role",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<Role> roles = new HashSet<>();
public User() {
}
public User(Long id, String firstName, String lastName, String email, String password) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.password = password;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public void setPassword(String password) {
this.password = password;
}
public Set<Role> getRoles() {
return roles;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return roles.stream().map(role -> new SimpleGrantedAuthority(role.getAuthority()))
.collect(Collectors.toList());
}
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return email;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(id, user.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
当您从安全包中扩展 UserDetails 类时,getAuthorities 方法默认返回 null,您需要实现类似的东西:
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return roles.stream().map(role -> new SimpleGrantedAuthority(role.getAuthority()))
.collect(Collectors.toList());
}
我希望这对某人有所帮助,抱歉我的英语错误!呵呵