Authenticatie met Reddit OAuth2 en Spring Security

1. Overzicht

In deze zelfstudie gebruiken we Spring Security OAuth om te verifiëren met de Reddit API.

2. Maven-configuratie

Ten eerste moeten we, om Spring Security OAuth te gebruiken, de volgende afhankelijkheid toevoegen aan onze pom.xml (natuurlijk naast elke andere Spring-afhankelijkheid die u zou kunnen gebruiken):

 org.springframework.security.oauth spring-security-oauth2 2.0.6.RELEASE 

3. Configureer OAuth2 Client

Laten we vervolgens onze OAuth2-client configureren: het OAuth2RestTemplate - en een reddit.properties bestand voor alle authenticatiegerelateerde eigenschappen:

@Configuration @ EnableOAuth2Client @PropertySource ("classpath: reddit.properties") beschermde statische klasse ResourceConfiguration {@Value ("$ {accessTokenUri}") private String accessTokenUri; @Value ("$ {userAuthorizationUri}") private String userAuthorizationUri; @Value ("$ {clientID}") private String clientID; @Value ("$ {clientSecret}") private String clientSecret; @Bean openbaar OAuth2ProtectedResourceDetails reddit () {AuthorizationCodeResourceDetails details = nieuwe AuthorizationCodeResourceDetails (); details.setId ("reddit"); details.setClientId (clientID); details.setClientSecret (clientSecret); details.setAccessTokenUri (accessTokenUri); details.setUserAuthorizationUri (userAuthorizationUri); details.setTokenName ("oauth_token"); details.setScope (Arrays.asList ("identiteit")); details.setPreEstablishedRedirectUri ("// localhost / login"); details.setUseCurrentUri (false); details retourneren; } @Bean openbare OAuth2RestTemplate redditRestTemplate (OAuth2ClientContext clientContext) {OAuth2RestTemplate-sjabloon = nieuwe OAuth2RestTemplate (reddit (), clientContext); AccessTokenProvider accessTokenProvider = nieuwe AccessTokenProviderChain (Arrays. AsList (nieuwe MyAuthorizationCodeAccessTokenProvider (), nieuwe ImplicitAccessTokenProvider (), nieuwe ResourceOwnerPasswordAccessTokenProvider (), nieuwe ClientCredentialsAccess )TokenProvider; template.setAccessTokenProvider (accessTokenProvider); retour sjabloon; }}

En "reddit.properties“:

clientID = xxxxxxxx clientSecret = xxxxxxxx accessTokenUri = // www.reddit.com/api/v1/access_token userAuthorizationUri = // www.reddit.com/api/v1/authorize

U kunt uw eigen geheime code krijgen door een Reddit-app te maken van //www.reddit.com/prefs/apps/

We gaan de OAuth2RestTemplate naar:

  1. Verkrijg het toegangstoken dat nodig is om toegang te krijgen tot de externe bron.
  2. Toegang tot de externe bron nadat u het toegangstoken hebt verkregen.

Merk ook op hoe we het bereik hebben toegevoegd "identiteit”Naar Reddit OAuth2ProtectedResourceDetails zodat we de accountgegevens van de gebruikers later kunnen ophalen.

4. Aangepast AuthorizationCodeAccessTokenProvider

De Reddit OAuth2-implementatie wijkt een beetje af van de standaard. En dus - in plaats van de AuthorizationCodeAccessTokenProvider - we moeten sommige delen ervan daadwerkelijk opheffen.

Er zijn github-problemen met het bijhouden van verbeteringen waardoor dit niet nodig is, maar deze problemen zijn nog niet opgelost.

Een van de niet-standaard dingen die Reddit doet, is: wanneer we de gebruiker omleiden en hem vragen om te authenticeren met Reddit, moeten we enkele aangepaste parameters in de omleidings-URL hebben. Meer specifiek - als we om een ​​permanent toegangstoken van Reddit vragen - moeten we een parameter toevoegen “looptijd"Met de waarde"permanent“.

Dus na verlenging AuthorizationCodeAccessTokenProvider - we hebben deze parameter toegevoegd in het getRedirectForAuthorization () methode:

 requestParameters.put ("duration", "permanent");

U kunt hier de volledige broncode bekijken.

5. Het ServerInitializer

Vervolgens - laten we onze aangepaste maken ServerInitializer.

We moeten een filterboon toevoegen met id oauth2ClientContextFilter, zodat we het kunnen gebruiken om de huidige context op te slaan:

openbare klasse ServletInitializer breidt AbstractDispatcherServletInitializer uit {@Override beschermde WebApplicationContext createServletApplicationContext () {AnnotationConfigWebApplicationContext context = nieuwe AnnotationConfigWebApplicationContext (); context.register (WebConfig.class, SecurityConfig.class); context teruggeven; } @Override beschermde String [] getServletMappings () {retourneer nieuwe String [] {"/"}; } @Override beschermde WebApplicationContext createRootApplicationContext () {return null; } @Override public void onStartup (ServletContext servletContext) gooit ServletException {super.onStartup (servletContext); registerProxyFilter (servletContext, "oauth2ClientContextFilter"); registerProxyFilter (servletContext, "springSecurityFilterChain"); } private void registerProxyFilter (ServletContext servletContext, String naam) {DelegatingFilterProxy filter = nieuwe DelegatingFilterProxy (naam); filter.setContextAttribute ("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher"); servletContext.addFilter (naam, filter) .addMappingForUrlPatterns (null, false, "/ *"); }}

6. MVC-configuratie

Laten we nu eens kijken naar onze MVC-configuratie van onze eenvoudige web-app:

@Configuration @EnableWebMvc @ComponentScan (basePackages = {"org.baeldung.web"}) openbare klasse WebConfig implementeert WebMvcConfigurer {@Bean openbare statische PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer () {retourneer nieuwe PropertySourcesPlaceholderConfigurer (); } @Bean openbare ViewResolver viewResolver () {InternalResourceViewResolver viewResolver = nieuwe InternalResourceViewResolver (); viewResolver.setPrefix ("/ WEB-INF / jsp /"); viewResolver.setSuffix (". jsp"); terug viewResolver; } @Override public void configureDefaultServletHandling (DefaultServletHandlerConfigurer configurer) {configurer.enable (); } public void addResourceHandlers (register ResourceHandlerRegistry) {registry.addResourceHandler ("/ resources / **"). addResourceLocations ("/ resources /"); } @Override public void addViewControllers (ViewControllerRegistry-register) {registry.addViewController ("/ home.html"); }}

7. Beveiligingsconfiguratie

Volgende - laten we eens kijken de belangrijkste Spring Security-configuratie:

@Configuration @EnableWebSecurity openbare klasse SecurityConfig breidt WebSecurityConfigurerAdapter uit {@Override protected void configure (AuthenticationManagerBuilder auth) gooit Uitzondering {auth.inMemoryAuthentication (); } @Override protected void configure (HttpSecurity http) gooit uitzondering {http .anonymous (). Disable () .csrf (). Disable () .authorizeRequests () .antMatchers ("/ home.html"). HasRole ("USER" ) .en () .httpBasic () .authenticationEntryPoint (oauth2AuthenticationEntryPoint ()); } privé LoginUrlAuthenticationEntryPoint oauth2AuthenticationEntryPoint () {retourneer nieuwe LoginUrlAuthenticationEntryPoint ("/ login"); }}

Opmerking: we hebben een eenvoudige beveiligingsconfiguratie toegevoegd die omleidt naar '/Log in”Die de gebruikersinformatie ophalen en de authenticatie ervan laden - zoals uitgelegd in de volgende sectie.

8. RedditController

Laten we nu eens kijken naar onze controller RedditController.

We gebruiken methode redditLogin () om de gebruikersinformatie van zijn Reddit-account te krijgen en er een authenticatie van te laden - zoals in het volgende voorbeeld:

@Controller openbare klasse RedditController {@Autowired privé OAuth2RestTemplate redditRestTemplate; @RequestMapping ("/ login") openbare String redditLogin () {JsonNode node = redditRestTemplate.getForObject ("//oauth.reddit.com/api/v1/me", JsonNode.class); UsernamePasswordAuthenticationToken auth = nieuwe UsernamePasswordAuthenticationToken (node.get ("name"). AsText (), redditRestTemplate.getAccessToken (). GetValue (), Arrays.asList (nieuwe SimpleGrantedAuthority ("ROLE_USER"))); SecurityContextHolder.getContext (). SetAuthentication (auth); retourneer "redirect: home.html"; }}

Een interessant detail van deze bedrieglijk eenvoudige methode: de reddit-sjabloon controleert of het toegangstoken beschikbaar is voordat een verzoek wordt uitgevoerd; het verkrijgt een token als er geen beschikbaar is.

Vervolgens presenteren we de informatie aan onze zeer simplistische front-end.

9. home.jsp

Eindelijk - laten we eens kijken home.jsp - om de informatie die is opgehaald uit het Reddit-account van de gebruiker weer te geven:

10. Conclusie

In dit inleidende artikel hebben we onderzocht authenticeren met de Reddit OAuth2 API en het weergeven van een aantal zeer basale informatie in een eenvoudige front-end.

Nu we zijn geverifieerd, gaan we in het volgende artikel van deze nieuwe serie onderzoeken hoe interessantere dingen kunnen worden gedaan met de Reddit API.

De volledige implementatie van deze tutorial is te vinden in het github-project - dit is een op Eclipse gebaseerd project, dus het zou gemakkelijk te importeren en uit te voeren moeten zijn zoals het is.