OAuth2 hasRole始终返回401

时间:2017-06-11 11:19:36

标签: java security spring-boot oauth-2.0 http-status-code-401

我尝试使用OAuth2创建Spring Boot App。我创建了User类,定义如下:

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;

@NotNull
private String username;

@NotNull
private String password;

@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Role> roles;

我创建了用户&#34; test&#34;有两个角色:&#34; USER&#34;和&#34; ADMIN&#34;,但当我想发送POST请求到&#34; / get&#34;处理程序我获得401状态。 我的ResourceServerConfig:

@Autowired
private TokenStore tokenStore;

@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
    resources.resourceId("resource").tokenStore(tokenStore);
}

@Override
public void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .antMatchers("/").permitAll()
        .antMatchers("/msg/**").authenticated()
        .antMatchers("/get/**").hasRole("ADMIN");
}

AuthorizationServerConfig @Autowired     private AuthenticationManager authenticationManager;

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.inMemory().withClient("trustedClient")
        .authorizedGrantTypes("client_credentials","password")
        .authorities("ROLE_CLIENT","ROLE_TRUSTED_CLIENT")
        .scopes("read","write","trust")
        .accessTokenValiditySeconds(5000)
        .secret("secret");
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    endpoints.pathMapping("/oauth/token", "/login")
        .tokenEnhancer(tokenEnhancer())
        .tokenStore(tokenStore())
        .authenticationManager(authenticationManager);
}

@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
    security.checkTokenAccess("isAuthenticated()");
}

@Bean
public TokenEnhancer tokenEnhancer(){
    return new CustomTokenEnhancer();
}

@Bean
public TokenStore tokenStore(){
    return new InMemoryTokenStore();
}

CustomTokenEnhancer

@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
    CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
    User user = new User();
    user.setUsername(userDetails.getUsername());
    user.setPassword(userDetails.getPassword());
    List<Role> roles = new ArrayList<>();
    for(GrantedAuthority role: userDetails.getAuthorities())
        roles.add(new Role(role.getAuthority()));
    user.setRoles(roles);

    Map<String, Object> additional = new HashMap<>();
    additional.put("user", user);

    ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additional);
    return accessToken;
}

和最后一个CustomUserDetails

public CustomUserDetails(User byUsername){
    this.username = byUsername.getUsername();
    this.password = byUsername.getPassword();

    List<GrantedAuthority> auths = new ArrayList<>();
    for(Role role: byUsername.getRoles())
        auths.add(new SimpleGrantedAuthority(role.getName().toUpperCase()));
    this.authorities = auths;
    System.out.println(this.authorities);
}

这最后一个println返回[USER,ADMIN]。

2 个答案:

答案 0 :(得分:0)

如果您的配置正确,那么默认情况下,用户角色应该具有&#39; ROLE _&#39;字首。只需将此前缀添加到用户&#39;角色和所有都应该有用。

如果在此更改后您仍然收到401状态,请尝试覆盖application.properties(application.yml)中的oauth过滤器顺序:

security:
  oauth2:
    resource:
      filter-order: 3

此问题与1.5版本以来spring oauth的最新变化有关。请查看此链接https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-1.5-Release-Notes#oauth-2-resource-filter

答案 1 :(得分:0)

更改此部分:

import sys
import re
import itertools
import builtins
from builtins import __build_class__

def build_class(func, name, *bases, metaclass=None, **kwds):
    if bases[-1] is object:
        bases = bases[:-1]
    bases += HackishClass, object
    if metaclass is None:
        return __build_class__(func, name, *bases, **kwds)
    return __build_class__(func, name, *bases, metaclass=metaclass, **kwds)

private_regex = re.compile('_(?P<class>.*?)__(?P<name>.*)')
class HackishClass:
    __slots__ = ()
    def __getattribute__(self, key):
        match = private_regex.match(key)
        if match is not None:
            for depth in itertools.count(1):
                frame = sys._getframe(depth)
                if ...:  # snip
                    # Check for the original attribute access here.
                    break
            class_name = ...  # HERE! MAGIC GOES HERE!
            if class_name != match['class']:
                raise AttributeError("This is private! Keep out.")
        return super().__getattribute__(key)

builtins.__build_class__ = build_class

收件人:

@Override
public void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
    .antMatchers("/").permitAll()
    .antMatchers("/msg/**").authenticated()
    .antMatchers("/get/**").hasRole("ADMIN");
}