[SPRING] Spring 보안 OAuth2는 JSON을 허용합니다.
SPRINGSpring 보안 OAuth2는 JSON을 허용합니다.
나는 봄 OAuth2로 시작하고있다. POST 본체의 application / json 형식으로 / oauth / token endpoint에 사용자 이름과 암호를 보내고 싶습니다.
curl -X POST -H "Authorization: Basic YWNtZTphY21lc2VjcmV0" -H "Content-Type: application/json" -d '{
"username": "user",
"password": "password",
"grant_type": "password"
}' "http://localhost:9999/api/oauth/token"
그게 가능하니?
나에게 조언을 해줄 수 있니?
해결법
-
==============================
1.해결책 (정확한지는 확실하지 않지만 작동하는 것 같습니다).
해결책 (정확한지는 확실하지 않지만 작동하는 것 같습니다).
자원 서버 구성 :
@Configuration public class ServerEndpointsConfiguration extends ResourceServerConfigurerAdapter { @Autowired JsonToUrlEncodedAuthenticationFilter jsonFilter; @Override public void configure(HttpSecurity http) throws Exception { http .addFilterBefore(jsonFilter, ChannelProcessingFilter.class) .csrf().and().httpBasic().disable() .authorizeRequests() .antMatchers("/test").permitAll() .antMatchers("/secured").authenticated(); } }
필터:
@Component @Order(value = Integer.MIN_VALUE) public class JsonToUrlEncodedAuthenticationFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (Objects.equals(request.getContentType(), "application/json") && Objects.equals(((RequestFacade) request).getServletPath(), "/oauth/token")) { InputStream is = request.getInputStream(); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); int nRead; byte[] data = new byte[16384]; while ((nRead = is.read(data, 0, data.length)) != -1) { buffer.write(data, 0, nRead); } buffer.flush(); byte[] json = buffer.toByteArray(); HashMap<String, String> result = new ObjectMapper().readValue(json, HashMap.class); HashMap<String, String[]> r = new HashMap<>(); for (String key : result.keySet()) { String[] val = new String[1]; val[0] = result.get(key); r.put(key, val); } String[] val = new String[1]; val[0] = ((RequestFacade) request).getMethod(); r.put("_method", val); HttpServletRequest s = new MyServletRequestWrapper(((HttpServletRequest) request), r); chain.doFilter(s, response); } else { chain.doFilter(request, response); } } @Override public void destroy() { } }
요청 래퍼 :
public class MyServletRequestWrapper extends HttpServletRequestWrapper { private final HashMap<String, String[]> params; public MyServletRequestWrapper(HttpServletRequest request, HashMap<String, String[]> params) { super(request); this.params = params; } @Override public String getParameter(String name) { if (this.params.containsKey(name)) { return this.params.get(name)[0]; } return ""; } @Override public Map<String, String[]> getParameterMap() { return this.params; } @Override public Enumeration<String> getParameterNames() { return new Enumerator<>(params.keySet()); } @Override public String[] getParameterValues(String name) { return params.get(name); } }
권한 서버 구성 (/ oauth / token 엔드 포인트에 대한 기본 인증 사용 불가능 :
@Configuration public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { ... @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer.allowFormAuthenticationForClients(); // Disable /oauth/token Http Basic Auth } ... }
-
==============================
2.OAuth 2 사양에서,
OAuth 2 사양에서,
액세스 토큰 요청은 application / x-www-form-urlencoded를 사용해야합니다.
Spring 보안에서 Resource Owner Password Credential은 Spring Security의 ResourceOwnerPasswordTokenGranter # getOAuth2Authentication에 의해 처리됩니다 :
protected OAuth2Authentication getOAuth2Authentication(AuthorizationRequest clientToken) { Map parameters = clientToken.getAuthorizationParameters(); String username = (String)parameters.get("username"); String password = (String)parameters.get("password"); UsernamePasswordAuthenticationToken userAuth = new UsernamePasswordAuthenticationToken(username, password);
요청 매개 변수에 사용자 이름과 암호를 보낼 수 있습니다.
JSON을 실제로 사용해야하는 경우 해결 방법이 있습니다. 보시다시피 요청 매개 변수에서 사용자 이름과 암호가 검색됩니다. 따라서 요청을 JSON 본문에서 요청 매개 변수로 전달하면 작동합니다.
아이디어는 다음과 같습니다.
희망이 도움이 될 수 있습니다.
-
==============================
3.또한 oauth에 대한 http 기본 인증을 지원하도록 @ jakub-kopřiva 솔루션을 수정할 수 있습니다.
또한 oauth에 대한 http 기본 인증을 지원하도록 @ jakub-kopřiva 솔루션을 수정할 수 있습니다.
자원 서버 구성 :
@Configuration public class ServerEndpointsConfiguration extends ResourceServerConfigurerAdapter { @Autowired JsonToUrlEncodedAuthenticationFilter jsonFilter; @Override public void configure(HttpSecurity http) throws Exception { http .addFilterAfter(jsonFilter, BasicAuthenticationFilter.class) .csrf().disable() .authorizeRequests() .antMatchers("/test").permitAll() .antMatchers("/secured").authenticated(); } }
내부 RequestWrapper로 필터링
@Component public class JsonToUrlEncodedAuthenticationFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (Objects.equals(request.getServletPath(), "/oauth/token") && Objects.equals(request.getContentType(), "application/json")) { byte[] json = ByteStreams.toByteArray(request.getInputStream()); Map<String, String> jsonMap = new ObjectMapper().readValue(json, Map.class);; Map<String, String[]> parameters = jsonMap.entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, e -> new String[]{e.getValue()}) ); HttpServletRequest requestWrapper = new RequestWrapper(request, parameters); filterChain.doFilter(requestWrapper, response); } else { filterChain.doFilter(request, response); } } private class RequestWrapper extends HttpServletRequestWrapper { private final Map<String, String[]> params; RequestWrapper(HttpServletRequest request, Map<String, String[]> params) { super(request); this.params = params; } @Override public String getParameter(String name) { if (this.params.containsKey(name)) { return this.params.get(name)[0]; } return ""; } @Override public Map<String, String[]> getParameterMap() { return this.params; } @Override public Enumeration<String> getParameterNames() { return new Enumerator<>(params.keySet()); } @Override public String[] getParameterValues(String name) { return params.get(name); } } }
또한 x-www-form-urlencoded 인증을 허용해야합니다.
@Configuration public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { ... @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer.allowFormAuthenticationForClients(); } ... }
이 방법을 사용하면 다음과 같이 oauth 토큰에 기본 인증을 사용할 수 있고 json으로 토큰을 요청할 수 있습니다.
머리글:
Authorization: Basic bG9yaXpvbfgzaWNwYQ==
신체:
{ "grant_type": "password", "username": "admin", "password": "1234" }
-
==============================
4.스프링 시큐리티 5에서는 .oldFormAuthenticationForClients () + JsontoUrlEncodedAuthenticationFilter를 추가해야만 x- 폼 포스트 데이터 외에도 json을 받아들이도록 할 수 있었다. 리소스 서버 등을 등록 할 필요가 없었습니다.
스프링 시큐리티 5에서는 .oldFormAuthenticationForClients () + JsontoUrlEncodedAuthenticationFilter를 추가해야만 x- 폼 포스트 데이터 외에도 json을 받아들이도록 할 수 있었다. 리소스 서버 등을 등록 할 필요가 없었습니다.
-
==============================
5.@ jakub-kopřiva 솔루션을 수정하여 아래 코드로 권한 부여 서버 만 구현할 수 있습니다.
@ jakub-kopřiva 솔루션을 수정하여 아래 코드로 권한 부여 서버 만 구현할 수 있습니다.
@Configuration @Order(Integer.MIN_VALUE) public class AuthorizationServerSecurityConfiguration extends org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerSecurityConfiguration { @Autowired JsonToUrlEncodedAuthenticationFilter jsonFilter; @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity .addFilterBefore(jsonFilter, ChannelProcessingFilter.class); super.configure(httpSecurity); } }
from https://stackoverflow.com/questions/38165131/spring-security-oauth2-accept-json by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Spring boot rest service에서 파일을 다운로드한다. (0) | 2019.01.15 |
---|---|
[SPRING] 메이븐 (maven)과 부두 (jetty)를 사용하여 실행 가능한 항아리 만들기 (0) | 2019.01.15 |
[SPRING] 임베디드 바람둥이에 사용자 정의 web.xml 지정 (0) | 2019.01.15 |
[SPRING] 비동기식으로 긴 폴링 구현 (0) | 2019.01.15 |
[SPRING] 리바운드 라이브러리를 사용하여 Facebook Messenger 채팅 헤드와 동일한 ImageView에 자연스러운 끌기 효과 추가 (0) | 2019.01.15 |