1. Übersicht
In diesem Tutorial verwenden wir Spring Security OAuth zur Authentifizierung bei der Reddit-API.
2. Maven-Konfiguration
Um Spring Security OAuth verwenden zu können, müssen wir unserer pom.xml die folgende Abhängigkeit hinzufügen (natürlich zusammen mit jeder anderen Spring-Abhängigkeit, die Sie möglicherweise verwenden):
org.springframework.security.oauth spring-security-oauth2 2.0.6.RELEASE
3. Konfigurieren Sie den OAuth2-Client
Als Nächstes konfigurieren wir unseren OAuth2-Client - das OAuth2RestTemplate - und eine reddit.properties- Datei für alle authentifizierungsbezogenen Eigenschaften:
@Configuration @EnableOAuth2Client @PropertySource("classpath:reddit.properties") protected static class ResourceConfiguration { @Value("${accessTokenUri}") private String accessTokenUri; @Value("${userAuthorizationUri}") private String userAuthorizationUri; @Value("${clientID}") private String clientID; @Value("${clientSecret}") private String clientSecret; @Bean public OAuth2ProtectedResourceDetails reddit() { AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails(); details.setId("reddit"); details.setClientId(clientID); details.setClientSecret(clientSecret); details.setAccessTokenUri(accessTokenUri); details.setUserAuthorizationUri(userAuthorizationUri); details.setTokenName("oauth_token"); details.setScope(Arrays.asList("identity")); details.setPreEstablishedRedirectUri("//localhost/login"); details.setUseCurrentUri(false); return details; } @Bean public OAuth2RestTemplate redditRestTemplate(OAuth2ClientContext clientContext) { OAuth2RestTemplate template = new OAuth2RestTemplate(reddit(), clientContext); AccessTokenProvider accessTokenProvider = new AccessTokenProviderChain( Arrays. asList( new MyAuthorizationCodeAccessTokenProvider(), new ImplicitAccessTokenProvider(), new ResourceOwnerPasswordAccessTokenProvider(), new ClientCredentialsAccessTokenProvider()) ); template.setAccessTokenProvider(accessTokenProvider); return template; } }
Und „ reddit.properties “:
clientID=xxxxxxxx clientSecret=xxxxxxxx accessTokenUri=//www.reddit.com/api/v1/access_token userAuthorizationUri=//www.reddit.com/api/v1/authorize
Sie können Ihren eigenen Geheimcode erhalten, indem Sie eine Reddit-App unter //www.reddit.com/prefs/apps/ erstellen.
Wir werden die OAuth2RestTemplate verwenden, um:
- Erwerben Sie das Zugriffstoken, das für den Zugriff auf die Remote-Ressource erforderlich ist.
- Greifen Sie auf die Remote-Ressource zu, nachdem Sie das Zugriffstoken erhalten haben.
Beachten Sie auch, wie wir Reddit OAuth2ProtectedResourceDetails den Bereich " Identität " hinzugefügt haben, damit wir die Kontoinformationen des Benutzers später abrufen können.
4. Benutzerdefinierter AuthorizationCodeAccessTokenProvider
Die Reddit OAuth2-Implementierung unterscheidet sich ein wenig vom Standard. Anstatt den AuthorizationCodeAccessTokenProvider elegant zu erweitern, müssen wir einige Teile davon tatsächlich überschreiben.
Es gibt Github-Probleme bei der Verfolgung von Verbesserungen, die dies nicht erforderlich machen, aber diese Probleme sind noch nicht behoben.
Eine der nicht standardmäßigen Aufgaben von Reddit ist: Wenn wir den Benutzer umleiten und ihn zur Authentifizierung bei Reddit auffordern, müssen einige benutzerdefinierte Parameter in der Umleitungs-URL enthalten sein. Genauer gesagt - wenn wir von Reddit nach einem permanenten Zugriffstoken fragen - müssen wir einen Parameter " Dauer " mit dem Wert " permanent " hinzufügen .
Nach der Erweiterung von AuthorizationCodeAccessTokenProvider haben wir diesen Parameter in die Methode getRedirectForAuthorization () eingefügt :
requestParameters.put("duration", "permanent");
Sie können den vollständigen Quellcode von hier aus überprüfen.
5. Der ServerInitializer
Als Nächstes erstellen wir unseren benutzerdefinierten ServerInitializer .
Wir müssen eine Filter-Bean mit der ID oauth2ClientContextFilter hinzufügen , damit wir damit den aktuellen Kontext speichern können:
public class ServletInitializer extends AbstractDispatcherServletInitializer { @Override protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.register(WebConfig.class, SecurityConfig.class); return context; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } @Override protected WebApplicationContext createRootApplicationContext() { return null; } @Override public void onStartup(ServletContext servletContext) throws ServletException { super.onStartup(servletContext); registerProxyFilter(servletContext, "oauth2ClientContextFilter"); registerProxyFilter(servletContext, "springSecurityFilterChain"); } private void registerProxyFilter(ServletContext servletContext, String name) { DelegatingFilterProxy filter = new DelegatingFilterProxy(name); filter.setContextAttribute( "org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher"); servletContext.addFilter(name, filter).addMappingForUrlPatterns(null, false, "/*"); } }
6. MVC-Konfiguration
Schauen wir uns jetzt unsere MVC-Konfiguration unserer einfachen Web-App an:
@Configuration @EnableWebMvc @ComponentScan(basePackages = { "org.baeldung.web" }) public class WebConfig implements WebMvcConfigurer { @Bean public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } @Bean public ViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/jsp/"); viewResolver.setSuffix(".jsp"); return viewResolver; } @Override public void configureDefaultServletHandling( DefaultServletHandlerConfigurer configurer) { configurer.enable(); } public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**").addResourceLocations("/resources/"); } @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/home.html"); } }
7. Sicherheitskonfiguration
Als nächstes werfen wir einen Blick auf die Hauptkonfiguration von Spring Security :
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication(); } @Override protected void configure(HttpSecurity http) throws Exception { http .anonymous().disable() .csrf().disable() .authorizeRequests() .antMatchers("/home.html").hasRole("USER") .and() .httpBasic() .authenticationEntryPoint(oauth2AuthenticationEntryPoint()); } private LoginUrlAuthenticationEntryPoint oauth2AuthenticationEntryPoint() { return new LoginUrlAuthenticationEntryPoint("/login"); } }
Hinweis: Wir haben eine einfache Sicherheitskonfiguration hinzugefügt, die zu " / login " umleitet, um die Benutzerinformationen abzurufen und die Authentifizierung daraus zu laden - wie im folgenden Abschnitt erläutert.
8. RedditController
Schauen wir uns jetzt unseren Controller RedditController an .
We use method redditLogin() to get the user information from his Reddit account and load an authentication from it – as in the following example:
@Controller public class RedditController { @Autowired private OAuth2RestTemplate redditRestTemplate; @RequestMapping("/login") public String redditLogin() { JsonNode node = redditRestTemplate.getForObject( "//oauth.reddit.com/api/v1/me", JsonNode.class); UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(node.get("name").asText(), redditRestTemplate.getAccessToken().getValue(), Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"))); SecurityContextHolder.getContext().setAuthentication(auth); return "redirect:home.html"; } }
An interesting detail of this deceptively simple method – the reddit template checks if the access token is available before executing any request; it acquires a token if one is not available.
Next – we present the information to our very simplistic front end.
9. home.jsp
Finally – let's take a look at home.jsp – to display the information retrieved form user's Reddit account:
10. Conclusion
In this introductory article, we explored authenticating with the Reddit OAuth2 API and displaying some very basic information in a simple front end.
Nachdem wir uns authentifiziert haben, werden wir im nächsten Artikel dieser neuen Serie untersuchen, wie Sie mit der Reddit-API interessantere Dinge tun können.
Die vollständige Implementierung dieses Tutorials finden Sie im Github-Projekt. Dies ist ein Eclipse-basiertes Projekt, daher sollte es einfach zu importieren und auszuführen sein.