在Spring Boot中配置0-legged OAuth 1.0

我想设置一个带有0-legged(因此没有请求或访问令牌)OAuth 1.0的Spring启动应用程序。 我一直在寻找一个例子,我一直在努力寻找如何使用新风格(没有xml)配置东西。

现在我只想得到一个简单的用例,其中只有1个路径(/ oauth)受OAuth保护(其他一切都只是大开),并且它使用自定义ConsumerDetailsS​​ervice (请参阅下面的代码的简单版本)。

这是我的WebSecurityConfigurerAdapter (我的Application.java旁边的SecurityConfiguration.java,我认为这是在spring启动应用程序中配置这种东西的正确方法)。 我很确定我错过了提供程序配置(如http://projects.spring.io/spring-security-oauth/docs/oauth1.html中提到的那样),但我的反复试验并没有产生结果。

@Configuration @EnableWebMvcSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { // 0-Legged OAuth on the /oauth and /lti paths only http.requestMatchers().antMatchers("/oauth"); // .and().... what? // ??? something must be missing here - provider? } } 

我在我的maven pom.xml中也有这个:

   org.springframework.boot spring-boot-starter-security    org.springframework.security.oauth spring-security-oauth 2.0.2.RELEASE  

我的自定义ConsumerDetailsS​​ervice

 @Component public class LTIConsumerDetailsService implements ConsumerDetailsService { @Override public ConsumerDetails loadConsumerByConsumerKey(String consumerKey) throws OAuthException { BaseConsumerDetails cd; // TODO really lookup the key and related consumer details, for sample here we just hardcoded if ("key".equals(consumerKey)) { cd = new BaseConsumerDetails(); cd.setConsumerKey(consumerKey); cd.setSignatureSecret(new SharedConsumerSecretImpl("secret")); cd.setConsumerName("Sample consumerName"); cd.setRequiredToObtainAuthenticatedToken(false); // no token required (0-legged) cd.setResourceDescription("Sample consumer details - AZ"); cd.setResourceName("Sample resourceName"); } else { throw new OAuthException("For this example, key must be 'key'"); } return cd; } } 

任何有关如何使用此工作的建议或指向spring boot OAuth 1.0代码的建议都将非常感激。 请注意,我已经尝试查看单独的spring boot安全性和OAuth指南,但无法成功合并它们。

以下是我通过Java Config在spring-boot 1.1.4中使用0-legged OAuth 1.0的方法。

注意:在我的情况下,我只希望OAuth保护单个路径(/ oauth / **),因此如果您希望保护所有内容,那么您可以简化部分内容。 你可以在这里看到我的完整代码: https : //github.com/azeckoski/lti_starter

一旦你有了下面显示的最小部分,你应该能够运行你的spring-boot应用程序并在/ oauth用ConsumerKey:key和Secret:secret激活OAuth 1.0兼容请求并成功加载路径。

Application.java

重要说明 :(1)不要只将ZeroLeggedOAuthProviderProcessingFilter声明为Bean,如果这样做,它最终会影响所有路径(它会被弹簧自动拾取)(2)如果你想访问,NoAuthConfigurationAdapter必须在那里受保护路径外的安全数据(在本例中为/ oauth)

 @ComponentScan @Configuration @EnableAutoConfiguration @EnableWebMvcSecurity // enable spring security and web mvc hooks @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) public class Application extends WebMvcConfigurerAdapter { final static Logger log = LoggerFactory.getLogger(Application.class); public static void main(String[] args) { SpringApplication.run(Application.class, args); } // Spring Security @Autowired @Order(Ordered.HIGHEST_PRECEDENCE + 10) @SuppressWarnings("SpringJavaAutowiringInspection") public void configureSimpleAuthUsers(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("admin").password("admin").roles("ADMIN", "USER") .and().withUser("user").password("user").roles("USER"); } @Configuration @Order(1) // HIGHEST public static class OAuthSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { private ZeroLeggedOAuthProviderProcessingFilter zeroLeggedOAuthProviderProcessingFilter; @Autowired OAuthConsumerDetailsService oauthConsumerDetailsService; @Autowired OAuthAuthenticationHandler oauthAuthenticationHandler; @Autowired OAuthProcessingFilterEntryPoint oauthProcessingFilterEntryPoint; @Autowired OAuthProviderTokenServices oauthProviderTokenServices; @PostConstruct public void init() { zeroLeggedOAuthProviderProcessingFilter = new ZeroLeggedOAuthProviderProcessingFilter(oauthConsumerDetailsService, new InMemoryNonceServices(), oauthProcessingFilterEntryPoint, oauthAuthenticationHandler, oauthProviderTokenServices); } @Override protected void configure(HttpSecurity http) throws Exception { http.antMatcher("/oauth/**") .addFilterBefore(zeroLeggedOAuthProviderProcessingFilter, UsernamePasswordAuthenticationFilter.class) .authorizeRequests().anyRequest().hasRole("OAUTH"); } } @Order(45) // LOW @Configuration public static class BasicAuthConfigurationAdapter extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.antMatcher("/basic/**").authorizeRequests().anyRequest().authenticated() .and().httpBasic(); } } @Order(67) // LOWEST @Configuration public static class NoAuthConfigurationAdapter extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.antMatcher("/**").authorizeRequests().anyRequest().permitAll(); } } // OAuth beans public static class OAuthProcessingFilterEntryPointImpl extends OAuthProcessingFilterEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { log.info("OAuth FILTER Failure (commence), req=" + request + ", ex=" + authException); // Called when there is an OAuth Auth failure, authException may be InsufficientAuthenticationException super.commence(request, response, authException); } } @Bean(name = "oauthAuthenticationEntryPoint") public OAuthProcessingFilterEntryPoint oauthAuthenticationEntryPoint() { return new OAuthProcessingFilterEntryPointImpl(); } @Bean(name = "oauthProviderTokenServices") public OAuthProviderTokenServices oauthProviderTokenServices() { // NOTE: we don't use the OAuthProviderTokenServices for 0-legged but it cannot be null return new InMemoryProviderTokenServices(); } public static class ZeroLeggedOAuthProviderProcessingFilter extends ProtectedResourceProcessingFilter { ZeroLeggedOAuthProviderProcessingFilter(OAuthConsumerDetailsService oAuthConsumerDetailsService, OAuthNonceServices oAuthNonceServices, OAuthProcessingFilterEntryPoint oAuthProcessingFilterEntryPoint, OAuthAuthenticationHandler oAuthAuthenticationHandler, OAuthProviderTokenServices oAuthProviderTokenServices) { super(); log.info("CONSTRUCT Zero Legged OAuth provider"); setAuthenticationEntryPoint(oAuthProcessingFilterEntryPoint); setAuthHandler(oAuthAuthenticationHandler); setConsumerDetailsService(oAuthConsumerDetailsService); setNonceServices(oAuthNonceServices); setTokenServices(oAuthProviderTokenServices); //setIgnoreMissingCredentials(false); // die if OAuth params are not included } } } 

OAuthConsumerDetailsS​​ervice.java

 @Component public class OAuthConsumerDetailsService implements ConsumerDetailsService { final static Logger log = LoggerFactory.getLogger(OAuthConsumerDetailsService.class); @Override public ConsumerDetails loadConsumerByConsumerKey(String consumerKey) throws OAuthException { BaseConsumerDetails cd; // NOTE: really lookup the key and secret, for the sample here we just hardcoded if ("key".equals(consumerKey)) { // allow this oauth request cd = new BaseConsumerDetails(); cd.setConsumerKey(consumerKey); cd.setSignatureSecret(new SharedConsumerSecretImpl("secret")); cd.setConsumerName("Sample"); cd.setRequiredToObtainAuthenticatedToken(false); // no token required (0-legged) cd.getAuthorities().add(new SimpleGrantedAuthority("ROLE_OAUTH")); // add the ROLE_OAUTH (can add others as well) log.info("OAuth check SUCCESS, consumer key: " + consumerKey); } else { // deny - failed to match throw new OAuthException("For this example, key must be 'key'"); } return cd; } } 

MyOAuthAuthenticationHandler.java

最后一部分对于根据来自OAuth请求的数据定义实际用户(和Principal)非常重要。 这取决于您如何在本地处理事物,但这是如何做到这一点的一个例子。

 @Component public class MyOAuthAuthenticationHandler implements OAuthAuthenticationHandler { final static Logger log = LoggerFactory.getLogger(MyOAuthAuthenticationHandler.class); static SimpleGrantedAuthority userGA = new SimpleGrantedAuthority("ROLE_USER"); static SimpleGrantedAuthority adminGA = new SimpleGrantedAuthority("ROLE_ADMIN"); @Override public Authentication createAuthentication(HttpServletRequest request, ConsumerAuthentication authentication, OAuthAccessProviderToken authToken) { Collection authorities = new HashSet<>(authentication.getAuthorities()); // attempt to create a user Authority String username = request.getParameter("username"); if (StringUtils.isBlank(username)) { username = authentication.getName(); } // NOTE: you should replace this block with your real rules for determining OAUTH ADMIN roles if (username.equals("admin")) { authorities.add(userGA); authorities.add(adminGA); } else { authorities.add(userGA); } Principal principal = new NamedOAuthPrincipal(username, authorities, authentication.getConsumerCredentials().getConsumerKey(), authentication.getConsumerCredentials().getSignature(), authentication.getConsumerCredentials().getSignatureMethod(), authentication.getConsumerCredentials().getSignatureBaseString(), authentication.getConsumerCredentials().getToken() ); Authentication auth = new UsernamePasswordAuthenticationToken(principal, null, authorities); return auth; } public static class NamedOAuthPrincipal extends ConsumerCredentials implements Principal { public String name; public Collection authorities; public NamedOAuthPrincipal(String name, Collection authorities, String consumerKey, String signature, String signatureMethod, String signatureBaseString, String token) { super(consumerKey, signature, signatureMethod, signatureBaseString, token); this.name = name; this.authorities = authorities; } @Override public String getName() { return name; } public Collection getAuthorities() { return authorities; } } } 

OAuthController.java

 @Controller @RequestMapping("/oauth") public class OAuthController extends BaseController { @RequestMapping({"", "/"}) public String home(HttpServletRequest req, Principal principal, Model model) { return "home"; // name of the template } } 

pom.xml(maven – 只有关键部分)

  org.springframework.boot spring-boot-starter-web    org.springframework.boot spring-boot-starter-security    org.springframework.security.oauth spring-security-oauth 2.0.2.RELEASE