Java Spring安全OAuth2-如何使用OAuth2Authentication对象?

Java Spring安全OAuth2-如何使用OAuth2Authentication对象?,java,spring-mvc,spring-security,spring-boot,spring-security-oauth2,Java,Spring Mvc,Spring Security,Spring Boot,Spring Security Oauth2,我有OAuth2授权服务器,它提供用户信息: public class User implements Serializable, UserDetails { private Long userID; private String username; private String password; private String fullName; private String email; private String avatar; p

我有OAuth2授权服务器,它提供用户信息:

public class User implements Serializable, UserDetails {
    private Long userID;
    private String username;
    private String password;
    private String fullName;
    private String email;
    private String avatar;
    private boolean enabled;
    // etc
}

@RestController
@RequestMapping("/api")
public class APIController {

    @RequestMapping("/me")
    public User me(@AuthenticationPrincipal User activeUser) {
        return activeUser;
    }
}
我还将OAuth2客户机作为单独的Spring引导应用程序实现

@Configuration
@EnableOAuth2Sso
public class OAuth2ClientConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.logout()
            .and()
            .antMatcher("/**").authorizeRequests()
            .antMatchers("/login").permitAll()
            .anyRequest().authenticated();
    }
}
application.yml

security:
  user:
    password: none
  oauth2:
    client:
      clientId:     acme
      clientSecret: acmepassword
      accessTokenUri:       http://localhost:9080/sso/oauth/token
      userAuthorizationUri: http://localhost:9080/sso/oauth/authorize
    resource:
      userInfoUri:    http://localhost:9080/sso/api/me
用户验证成功:

@Controller
public class MainController {

    @RequestMapping(value = "/")
    public String index(Principal principal) {
        System.out.println(principal);
        // org.springframework.security.oauth2.provider.OAuth2Authentication@c2e723e8: Principal: superadmin; Credentials: [PROTECTED]; Authenticated: true; Details: remoteAddress=<ADDRESS>, sessionId=<SESSION>, tokenType=bearertokenValue=<TOKEN>; Granted Authorities: {userRoleID=1, authority=ROLE_SUPERUSER}
        OAuth2Authentication auth = (OAuth2Authentication) principal;
        System.out.println(auth.getUserAuthentication().getDetails());
        // {userID=1, username=superadmin, password=***, fullName=SuperUser, email=superadmin@example.org, avatar=null, enabled=true ...
        return "index";
    }
}
标准Spring安全方法
isUserInRole()
也不起作用:

System.out.println(servletRequest.isUserInRole("ROLE_SUPERUSER"));
// false

我应该实现自定义Thymeleaf安全方言和hasRole()方法吗?或者可能存在更简单的解决方案?

好的,经过大量挖掘,我找到了解决方案

长话短说:应该重写方法以从OAuth2资源服务器响应中提取自定义主体和/或权限。封装在方法中的主逻辑

配置

@Configuration
@EnableOAuth2Sso
public class OAuth2ClientConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private ResourceServerProperties sso;

    @Autowired
    private OAuth2RestOperations restTemplate;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.logout().and().antMatcher("/**").authorizeRequests().antMatchers("/login").permitAll().anyRequest()
                        .authenticated();
    }

    @Bean
    // very important notice: method name should be exactly "userInfoTokenServices"
    public ResourceServerTokenServices userInfoTokenServices() {
        CustomUserInfoTokenServices serv = new CustomUserInfoTokenServices(sso.getUserInfoUri(), sso.getClientId());
        serv.setTokenType(sso.getTokenType());
        serv.setRestTemplate(restTemplate);
        return serv;
    }
}
服务

public class CustomUserInfoTokenServices implements ResourceServerTokenServices {
    // exactly the same as org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices
    // except extractAuthentication() method
}
PS

新的Spring Boot版本提供了更灵活的API。请参阅接口。不幸的是,它是在2周前添加的,在当前稳定的1.3.5.0版本中不受支持


希望这有助于使用
ResourceServerTokenServices
access\u token

@Autowired
ResourceServerTokenServices  resourceServerTokenServices;

OAuth2Authentication auth = resourceServerTokenServices.loadAuthentication(tokenId);
String principal = auth.getName();

principal
(如在
身份验证中。getPrincipal()
)通常是一个
字符串,因此我怀疑它是否有不同的属性。@M.Deinum感谢您的评论!找到了!Thymeleaf标记不起作用,因为方言操作的对象不包含
UserAuthentication
字段(这是存储自定义属性的地方)。我相信
isUserInRole()
方法不起作用,因为我使用了自定义
GrantedAuthority
对象。因此,我只需要将
主体
替换为
用户
,并将权限转换为一个适当的集合。您正在auth服务器上调用/oauth/check_令牌吗?
public class CustomUserInfoTokenServices implements ResourceServerTokenServices {
    // exactly the same as org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices
    // except extractAuthentication() method
}
@Autowired
ResourceServerTokenServices  resourceServerTokenServices;

OAuth2Authentication auth = resourceServerTokenServices.loadAuthentication(tokenId);
String principal = auth.getName();