首页 文章

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

提问于
浏览
11

我有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 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

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

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

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

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

..发生以下异常:

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

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

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

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

1 回答

  • 2

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

    简而言之:应该覆盖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

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

    希望这可以帮助

相关问题