java Spring Security OAuth2 - 如何使用 OAuth2Authentication 对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37544406/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 02:36:57  来源:igfitidea点击:

Spring Security OAuth2 - How to use OAuth2Authentication object?

javaspring-mvcspring-securityspring-bootspring-security-oauth2

提问by Vespin

I have OAuth2 authorization server which provides user information:

我有提供用户信息的 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;
    }
}

Also I've implemented OAuth2 client as separate Spring Boot application.

此外,我已将 OAuth2 客户端实现为单独的 Spring Boot 应用程序。

@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

应用程序.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

User authenticates successfully:

用户认证成功:

@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 protected], avatar=null, enabled=true ...
        return "index";
    }
}

But I can't understand how to use provided OAuth2Authentication object in my application. It almost useless.

但我无法理解如何在我的应用程序中使用提供的 OAuth2Authentication 对象。它几乎没用。

When I'm trying to use any Thymeleaf security tag

当我尝试使用任何 Thymeleaf 安全标签时

<span sec:authentication="principal.fullName">Username</span>
<span sec:authentication="principal.authorities">Authorities</span>
<span sec:authentication="principal.userAuthentication.details.fullName">Usernames</span>

.. the following exception occurs:

.. 发生以下异常:

Error retrieving value for property "property name here" of authentication object of class org.springframework.security.oauth2.provider.OAuth2Authentication

Standard Spring Security methods isUserInRole()not working too:

标准 Spring Security 方法isUserInRole()也不起作用:

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

Should I implement custom Thymeleaf security dialect and hasRole() method? Or maybe simpler solution exists?

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

回答by Vespin

Ok, after a lot of digging i've found solution.

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

Long story short: ResourceServerTokenServices.loadAuthentication()method should be overriden to extract custom principal and / or authorities from OAuth2 resource server response. Main logic encapsulated in extractAuthentication()method.

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

Config

配置

@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;
    }
}

Service

服务

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

PS:

附注

New Spring Bootversion provides more flexible API. See PrincipalExtractorinterface. Unfortunately it was added only 2 weeks ago and doesn't supported in current stable 1.3.5.RELEASEversion.

新的Spring Boot版本提供了更灵活的 API。见PrincipalExtractor界面。不幸的是,它仅在 2 周前添加,当前稳定的1.3.5.RELEASE版本不支持。

Hope this helps

希望这可以帮助