Автор оригинала: Eugen Paraschiv.
1. Обзор
В этом уроке мы будем использовать Spring Security OAuth для аутентификации с помощью API Reddit.
2. Конфигурация Maven
Во – первых, чтобы использовать Spring Security OAuth-нам нужно добавить следующую зависимость в наш pom.xml (конечно, вместе с любой другой зависимостью Spring, которую вы можете использовать):
org.springframework.security.oauth spring-security-oauth2 2.0.6.RELEASE
3. Настройте клиент OAuth2
Далее – давайте настроим наш клиент OAuth2 – файл OAuth2RestTemplate – и файл reddit.properties для всех свойств, связанных с проверкой подлинности:
@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("http://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; } }
И ” reddit.properties “:
clientID=xxxxxxxx clientSecret=xxxxxxxx accessTokenUri=https://www.reddit.com/api/v1/access_token userAuthorizationUri=https://www.reddit.com/api/v1/authorize
Вы можете получить свой собственный секретный код, создав приложение Reddit из https://www.reddit.com/prefs/apps/
Мы собираемся использовать OAuth2RestTemplate для:
- Получите маркер доступа, необходимый для доступа к удаленному ресурсу.
- Доступ к удаленному ресурсу после получения маркера доступа.
Также обратите внимание, как мы добавили область ” identity ” в Reddit OAuth2ProtectedResourceDetails , чтобы мы могли позже получить информацию об учетной записи пользователя.
4. Пользовательский AuthorizationCodeAccessTokenProvider
Реализация Reddit OAuth2 немного отличается от стандарта. И поэтому – вместо того, чтобы элегантно расширять AuthorizationCodeAccessTokenProvider – нам нужно фактически переопределить некоторые его части.
Есть проблемы с отслеживанием улучшений на github, которые сделают это ненужным, но эти проблемы еще не решены.
Одна из нестандартных вещей, которые делает Reddit, заключается в том, что когда мы перенаправляем пользователя и запрашиваем у него аутентификацию с помощью Reddit, нам нужно иметь некоторые пользовательские параметры в URL-адресе перенаправления. Более конкретно – если мы запрашиваем постоянный токен доступа от Reddit – нам нужно добавить параметр ” длительность “со значением” постоянный “.
Итак, после расширения AuthorizationCodeAccessTokenProvider – мы добавили этот параметр в метод getRedirectForAuthorization() :
requestParameters.put("duration", "permanent");
Вы можете проверить полный исходный код из здесь .
5. Инициализатор сервера
Далее – давайте создадим наш пользовательский ServerInitializer .
Нам нужно добавить компонент фильтра с идентификатором oauth2ClientContextFilter , чтобы мы могли использовать его для хранения текущего контекста:
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
Теперь – давайте взглянем на нашу конфигурацию MVC нашего простого веб-приложения:
@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. Конфигурация безопасности
Далее – давайте взглянем на основную конфигурацию безопасности Spring :
@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"); } }
Примечание: Мы добавили простую конфигурацию безопасности, которая перенаправляет на ” /login “, которая получает информацию о пользователе и загружает аутентификацию из нее – как описано в следующем разделе.
8. RedditController
Теперь – давайте взглянем на наш контроллер RedditController .
Мы используем метод redditLogin () , чтобы получить информацию о пользователе из его учетной записи Reddit и загрузить из нее аутентификацию – как в следующем примере:
@Controller public class RedditController { @Autowired private OAuth2RestTemplate redditRestTemplate; @RequestMapping("/login") public String redditLogin() { JsonNode node = redditRestTemplate.getForObject( "https://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"; } }
Интересная деталь этого обманчиво простого метода – шаблон reddit проверяет, доступен ли токен доступа перед выполнением любого запроса ; он получает токен, если он недоступен.
Далее – мы представляем информацию нашему очень упрощенному интерфейсу.
9. home.jsp
Наконец – давайте взглянем на home.jsp – для отображения информации, полученной из учетной записи пользователя Reddit:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>Welcome,
10. Заключение
В этой вводной статье мы исследовали аутентификацию с помощью API Reddit OAuth2 и отображение некоторой очень базовой информации в простом интерфейсе.
Теперь, когда мы прошли проверку подлинности, мы рассмотрим более интересные вещи с помощью API Reddit в следующей статье этой новой серии.
полную реализацию этого учебника можно найти в проекте github – это проект на основе Eclipse, поэтому его должно быть легко импортировать и запускать как есть.