ݺߣ

ݺߣShare a Scribd company logo
Clova Extension – OAuth구현 맛보기
Clova Platform Evangelist
옥상훈
2018-02-28
목차
• Clova extension – OAuth 갵Ӛ
• Clova extension 계정연동 개발과정
• OAuth 인증서버 개발
Clova extension OAuth 갵Ӛ
Clova extension 계정연동 서비스 목적
• 써드파티 회원 인증을 거친 사용자에게만 서비스를 제공하려 할 때
• 회원 가입 후 로그인한 사용자에게만 제공
• 써드파티 회원의 속성을 활용하는 서비스를 제공하려고 할 때
• 예) 나의 주문내역, 나의 예약 내역
Clova Extension - OAuth 예시 : 배달의 민족 회원 배달주소, 주문 메뉴설정
• https://blog.naver.com/clova_ai/221188646019
1
2
3
4
5
‘짱구신사’ 익스텐션 데모 시나리오
• 일반 시나리오
• 사용자: 클로바, 짱구신사를 시작해줘
• 익스텐션: 안녕하세요. 짱구신사가 시작되었습니다. 어느 지역 날씨를 알려드릴까요?
• 사용자: 서울 날씨를 알려줘.
• 익스텐션: 서울의 날씨는 맑음입니다.
• 계정연동 시나리오
• 사용자: 클로바, 짱구신사를 시작해줘
• 익스텐션: 안녕하세요. 짱구신사가 시작되었습니다. 어느 지역 날씨를 알려드릴까요?
• 사용자: 우리 동네 날씨 어때? (지역정보 없는 발화가 입력되면 회원정보에 설정된 지역명 조회 )
• 익스텐션: ***의 날씨는 맑음입니다.
Clova Extension - OAuth 흐름
1
2
3 4
5
1) Clova console 상에 익스텐션 tester로 등록되어 있으면 노출
2) 계정연동버튼
• Clova console에 계정연결여부가 ‘Y’이면 익스텐션 정보에 ’계정연동’버튼 노출
• 버튼을 누르면 Clova에서 OAuth2스펙에 따라 ‘로그인URL( Authorization URL ) ’로 설정된 웹페이지호출
3) 로그인 화면
• 써드파티 인증서버에서 제공하는 로그인 화면으로 회원 인증 진행
• 회원 인증에 성공하면, 2)단계에서 Clova가 넘겨준 OAuth 요청변수들을 ‘Access Token URI’ 로 요청전달
4) 접근권한 허용 화면
• 써드파티 인증서버에서 제공하는 접근권한 허용 화면
• 접근권한 허용하면 Clova가 넘겨준 redirect_uri로 이동 à 화면 5로 전환
5) 연동상태 허용 화면
• Clova에서는 익스텐션 서버로 요청을 보낼 때 accessToken 값을 같이 전송
Clova extension 계정연동 개발과정
Clova extension 계정연동 개발 과정
• Clova console에 익스텐션 등록
• 개발자콘솔에 기본정보, 서버정보, 계정연동 정보 등록
• 인터렉션 모델 구성
• 사용자 대화 시나리오 및 대화에 따른 처리할 Intent 및 slot 등록
• 익스텐션 API 서버 개발
• Clova로부터 Intent 요청을 받으면 이에 응답하는 API 개발
• 특정 API는 접근토큰이 있어야 응답가능하게 변경
• 인증 API 서버 개발
• Clova로부터 계정연동 페이지를 로딩하면 로그인페이지를 제공하고, 로그인 완료시 접근토큰을 발행
Clova console에 익스텐션 등록 - Extension 정보
Clova console에 익스텐션 등록 – 서버 연동 설정 - 1
Clova console에 익스텐션 등록 – 서버 연동 설정 - 2
OAuth 서버의 Endopoint URL à Controller에 구현
인터렉션 모델 구성
익스텐션 API 서버 개발
• 익스텐션서버
• REST API 서버로서, Clova platform은 Clova console에 등록한 REST API 서버URL로 응답과 요청을 주고
받습니다.
• Clova platform은 1) 익스텐션 실행 2) 인텐트 실행 3) 익스텐션 종료라는 3가지 type의 요청을 보내고, 익스
텐션 서버는 여기에 맞게 응답을 하면 됩니다.
• 익스텐션 서버는 https로 외부망으로 통신할 수 있는 서버이어야 하며, 포트는 80 또는 443로만 통신합니다.
서버가 처리해야할 작업
• Clova 요청 메시지의 request type에 따라 지정된 포맷의 응답 리
턴
• Request type
• LaunchRequest : 익스텐션의 시작 (“짱구박사 시작해줘” 했을 경우)
• SessionEndedRequest : 익스텐션의 종료 (“종료해줘” )
• IntentRequest
• Custom Intent à 개발자 콘솔에 입력한 Intent 와 Slot
• Built-in Intent à
https://developers.naver.com/console/clova/guide/CEK/References/CEK_API.md#cek-api-레퍼런스
OAuth 인증 API 서버 개발 – 주요 역할
• 회원 로그인
• 로그인 화면 제공 à Clova console에 등록한 ‘로그인 URL’에 해당
• 회원 인증 à 로그인 화면에서 입력한 id, pw에 대해 회원 인증 로직 구현
•
• 접근 토큰 발급
• 접근토큰 발행 대상 à Clova console에 등록한 ‘클라이언트 ID’와 ‘클라이언트
secret’이 대상
• Clova 는 Consumer, 써드파티 인증서버는 Provider 역할임
• 접근토큰 발행 : 회원 인증에 성공하면 Clova console에 등록한 ‘Access token
URI’로 요청을 보내고, 여기서 접근토큰을 발급 à 이후 Redirect URL로 이동
(https://prod-ni-cic.clova.ai/v1/al/token 로 고정되어 있음)
스펙: https://developers.naver.com/console/clova/guide/CEK/Guides/Link_User_Account.md
OAuth 인증 API 서버 개발 – 주요 작업
• 서버 구성
• 개발편의상 API 서버와 OAuth 서버는 하나의 서버로 제공
• 회원 정보 관리
• 회원 정보 및 인증 처리는 hard code로 처리
• 개발 환경
• SpringBoot 기반 : Web (API 서버) + Security (OAuth 서버)
OAuth 인증 API 서버 개발 – extension 처리 API
@RequestMapping(value = "/clova/extension", method= RequestMethod.POST, produces = "application/json" )
@ResponseBody
public ResponseEntity<MyExtensionMessage> weather (@RequestBody Map<String, Object> map) {
Map m = (HashMap)map.get("request");
String type = (String) m.get("type");
MyExtensionMessage mm = null;
if(type.equals("LaunchRequest")) { // extension 시작
mm= new MyExtensionMessage("안녕, 짱구 신사를 시작합니다. 어느 지역 날씨를 알려드릴까요 ?", false);
} else if (type.equals("IntentRequest")) { // extension의 인텐트 시작
…...........
} else if (type.equals(”SessionEndedRequest")) { // extension 종료
mm= new MyExtensionMessage("짱구 날씨를 종료합니다.", true);
}
return new ResponseEntity<MyExtensionMessage>(mm, HttpStatus.OK);
}
OAuth 인증 API 서버 개발 – extension 처리 API
if (intentName.equals("weatherIntent")) {
if (slots != null) {
Map myslot = (HashMap) slots.get("areaSlot");
if(myslot != null ) {
slotName = (String) myslot.get("name");
slotValue = (String) myslot.get("value");
System.out.println("slotName===" + slotName);
System.out.println("slotValue===" + slotValue);
} else {
// slot 이 없으면 사용자 정보에서
// 접근토큰을 이용해 사용자의 지역 정보 조회
slotValue = getUserArea(accessToken);
}
} else {
slotValue = getUserArea(accessToken);
}
mm = new MyExtensionMessage(intentName, slotValue + "의 날씨는 점점 따뜻해 지고 있어요.", false, "PlainText");
// Built-in Intent 처리
} else if (intentName.equals("Clova.YesIntent")) {
mm = new MyExtensionMessage(intentName, "예 라고 하셨나요?", true, "PlainText");
} else if (intentName.equals("Clova.NoIntent")) {
mm = new MyExtensionMessage(intentName, "노 라고 하셨나요?", true, "PlainText");
} else if (intentName.equals("Clova.GuideIntent")) {
mm = new MyExtensionMessage("hearTestIntent", "진주 날씨는 어때라고 해보세요", false, "PlainText");
} else if (intentName.equals("Clova.CancelIntent")) {
mm = new MyExtensionMessage("hearTestIntent", "짱구 신사 실행을 취소합니다. 안녕", true, "PlainText");
}
Extension 응답 message
처리 클래스
public class MyExtensionMessage {
public String version = "1.0";
public Map<String, Object> sessionAttributes = new HashMap();
public MyResponse response = null;
public MyExtensionMessage(String message, boolean session) {
MyResponseValue value = new MyResponseValue();
value.value = message;
if(!session) {
sessionAttributes.put("intent", "zzanguWeather");
}
MyResponse response = new MyResponse();
response.shouldEndSession = session;
response.outputSpeech.put("type", "SimpleSpeech");
response.outputSpeech.put("values", value);
this.response = response;
}
public static class MyResponse {
public Map<String, Object> outputSpeech = new
HashMap<String, Object>();
public Map<String, Map> card = new HashMap<String, Map>();
public ArrayList<String> directives = new ArrayList<String>();
public boolean shouldEndSession = false;
}
public static class MyResponseValue {
public String type = "PlainText";
public String lang = "ko";
public String value;
}
}
OAuth 인증 API 서버 개발 – 인증 처리 API
// 로그인 화면 html 로딩
@GetMapping("/clova/login")
@ResponseBody
public ModelAndView loginForm(HttpServletResponse httpServletResponse, @RequestParam("state") String state ) {
STATE_STRING = state;
return new ModelAndView("redirect:" + "/login.html");
}
@GetMapping("/clova/config")
@ResponseBody
public ModelAndView config( ) {
return new ModelAndView("redirect:" + "/config.html");
}
// login.html 에서 로그인 버튼 클릭시 접근토큰 발급 처리 (id, pw가 맞다고 가정 )
@PostMapping("/clova/login/check")
@ResponseBody
public void loginCheck(HttpServletResponse httpServletResponse, @RequestParam("userid") String userid, @RequestParam("passwd") String passwd,
@RequestParam("state") String state) throws IOException {
String redirect_uri = "https://prod-ni-cic.clova.ai/v1/al/token";
String url = "http://user:test@okgosu.net/oauth/authorize?response_type=code&client_id=clova&redirect_uri=" + redirect_uri +
"&scope=read&state="+STATE_STRING;
httpServletResponse.sendRedirect(url);
}
OAuth 인증 API 서버 개발 – 회원 API
@RequestMapping(value = "/clova/member", method= RequestMethod.POST,
produces = "application/json" )
@ResponseStatus(HttpStatus.CREATED)
Member create(@RequestBody Member member) {
return service.create(member);
}
@RequestMapping(value = "/clova/member", method=
RequestMethod.GET,produces = "application/json" )
Collection<Member> readList() {
return service.findAll();
}
@RequestMapping(value = "/clova/member/{id}", method= RequestMethod.GET,
produces = "application/json" )
ResponseEntity<Member> read(@PathVariable Integer id) {
Member b = service.findById(id);
return new ResponseEntity<Member>(b, HttpStatus.OK);
}
OAuth 인증 API 서버 개발 – 회원 관리 등록
@Service
public class MemberService {
private ConcurrentMap<Integer, Member> repo = new ConcurrentHashMap<>();
private AtomicInteger maxId = new AtomicInteger(0);
public MemberService() {
Member member = new Member("okgosu", "안드로메다");
Integer id = maxId.addAndGet(1);
member.setId(id);
repo.put(id, member);
}
public Member findById(Integer id) {
Member b = repo.get(id);
return b;
}
public boolean update(Member member) {
Member old = repo.put(member.getId(), member);
return old != null;
}
public Member create(Member member) {
Integer id = maxId.addAndGet(1);
member.setId(id);
repo.put(id, member);
return member;
}
public boolean delete(Integer id) {
Member old = repo.remove(id);
return old != null;
}
public Collection<Member> findAll() {
return repo.values();
}
}
Spring
Security
설정
@EnableResourceServer
@EnableAuthorizationServer
@SpringBootApplication
public class DemoApplication extends ResourceServerConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/clova/member").authenticated();
}
}
# application.properties
security.user.name=user
security.user.password=test
# client id, secret
security.oauth2.client.client-id=clova
security.oauth2.client.client-secret=clova123
security.enable-csrf=false
security.oauth2.client.scope=read
server.port=80
Thank you.
제휴문의: dl_clova_partnership@navercorp.com
Appendix.
• Clova Platform 발표자료 : /clovaplatform
• Clova 플랫폼 개발자 문서 : https://developers.naver.com/console/clova/guide/
• Design 챕터 / Clova Extensions Kit 챕터 / Clova Developer Console 챕터 참고
• 튜토리얼 및 샘플 코드 참고
• 샘플 코드 Github
• 마법 구슬 : https://github.com/naver/clova-extension-sample-magicball
• 빗소리 : https://github.com/naver/clova-extension-sample-rainsound
• 주사위 놀이 : https://github.com/naver/clova-extension-sample-dice
• 코인 헬퍼 : https://github.com/naver/clova-extension-sample-coinhelper

More Related Content

Clova extension에서 OAuth 계정 연동 구현

  • 1. Clova Extension – OAuth구현 맛보기 Clova Platform Evangelist 옥상훈 2018-02-28
  • 2. 목차 • Clova extension – OAuth 갵Ӛ • Clova extension 계정연동 개발과정 • OAuth 인증서버 개발
  • 4. Clova extension 계정연동 서비스 목적 • 써드파티 회원 인증을 거친 사용자에게만 서비스를 제공하려 할 때 • 회원 가입 후 로그인한 사용자에게만 제공 • 써드파티 회원의 속성을 활용하는 서비스를 제공하려고 할 때 • 예) 나의 주문내역, 나의 예약 내역
  • 5. Clova Extension - OAuth 예시 : 배달의 민족 회원 배달주소, 주문 메뉴설정 • https://blog.naver.com/clova_ai/221188646019 1 2 3 4 5
  • 6. ‘짱구신사’ 익스텐션 데모 시나리오 • 일반 시나리오 • 사용자: 클로바, 짱구신사를 시작해줘 • 익스텐션: 안녕하세요. 짱구신사가 시작되었습니다. 어느 지역 날씨를 알려드릴까요? • 사용자: 서울 날씨를 알려줘. • 익스텐션: 서울의 날씨는 맑음입니다. • 계정연동 시나리오 • 사용자: 클로바, 짱구신사를 시작해줘 • 익스텐션: 안녕하세요. 짱구신사가 시작되었습니다. 어느 지역 날씨를 알려드릴까요? • 사용자: 우리 동네 날씨 어때? (지역정보 없는 발화가 입력되면 회원정보에 설정된 지역명 조회 ) • 익스텐션: ***의 날씨는 맑음입니다.
  • 7. Clova Extension - OAuth 흐름 1 2 3 4 5
  • 8. 1) Clova console 상에 익스텐션 tester로 등록되어 있으면 노출 2) 계정연동버튼 • Clova console에 계정연결여부가 ‘Y’이면 익스텐션 정보에 ’계정연동’버튼 노출 • 버튼을 누르면 Clova에서 OAuth2스펙에 따라 ‘로그인URL( Authorization URL ) ’로 설정된 웹페이지호출 3) 로그인 화면 • 써드파티 인증서버에서 제공하는 로그인 화면으로 회원 인증 진행 • 회원 인증에 성공하면, 2)단계에서 Clova가 넘겨준 OAuth 요청변수들을 ‘Access Token URI’ 로 요청전달 4) 접근권한 허용 화면 • 써드파티 인증서버에서 제공하는 접근권한 허용 화면 • 접근권한 허용하면 Clova가 넘겨준 redirect_uri로 이동 à 화면 5로 전환 5) 연동상태 허용 화면 • Clova에서는 익스텐션 서버로 요청을 보낼 때 accessToken 값을 같이 전송
  • 10. Clova extension 계정연동 개발 과정 • Clova console에 익스텐션 등록 • 개발자콘솔에 기본정보, 서버정보, 계정연동 정보 등록 • 인터렉션 모델 구성 • 사용자 대화 시나리오 및 대화에 따른 처리할 Intent 및 slot 등록 • 익스텐션 API 서버 개발 • Clova로부터 Intent 요청을 받으면 이에 응답하는 API 개발 • 특정 API는 접근토큰이 있어야 응답가능하게 변경 • 인증 API 서버 개발 • Clova로부터 계정연동 페이지를 로딩하면 로그인페이지를 제공하고, 로그인 완료시 접근토큰을 발행
  • 11. Clova console에 익스텐션 등록 - Extension 정보
  • 12. Clova console에 익스텐션 등록 – 서버 연동 설정 - 1
  • 13. Clova console에 익스텐션 등록 – 서버 연동 설정 - 2 OAuth 서버의 Endopoint URL à Controller에 구현
  • 15. 익스텐션 API 서버 개발 • 익스텐션서버 • REST API 서버로서, Clova platform은 Clova console에 등록한 REST API 서버URL로 응답과 요청을 주고 받습니다. • Clova platform은 1) 익스텐션 실행 2) 인텐트 실행 3) 익스텐션 종료라는 3가지 type의 요청을 보내고, 익스 텐션 서버는 여기에 맞게 응답을 하면 됩니다. • 익스텐션 서버는 https로 외부망으로 통신할 수 있는 서버이어야 하며, 포트는 80 또는 443로만 통신합니다.
  • 16. 서버가 처리해야할 작업 • Clova 요청 메시지의 request type에 따라 지정된 포맷의 응답 리 턴 • Request type • LaunchRequest : 익스텐션의 시작 (“짱구박사 시작해줘” 했을 경우) • SessionEndedRequest : 익스텐션의 종료 (“종료해줘” ) • IntentRequest • Custom Intent à 개발자 콘솔에 입력한 Intent 와 Slot • Built-in Intent à https://developers.naver.com/console/clova/guide/CEK/References/CEK_API.md#cek-api-레퍼런스
  • 17. OAuth 인증 API 서버 개발 – 주요 역할 • 회원 로그인 • 로그인 화면 제공 à Clova console에 등록한 ‘로그인 URL’에 해당 • 회원 인증 à 로그인 화면에서 입력한 id, pw에 대해 회원 인증 로직 구현 • • 접근 토큰 발급 • 접근토큰 발행 대상 à Clova console에 등록한 ‘클라이언트 ID’와 ‘클라이언트 secret’이 대상 • Clova 는 Consumer, 써드파티 인증서버는 Provider 역할임 • 접근토큰 발행 : 회원 인증에 성공하면 Clova console에 등록한 ‘Access token URI’로 요청을 보내고, 여기서 접근토큰을 발급 à 이후 Redirect URL로 이동 (https://prod-ni-cic.clova.ai/v1/al/token 로 고정되어 있음) 스펙: https://developers.naver.com/console/clova/guide/CEK/Guides/Link_User_Account.md
  • 18. OAuth 인증 API 서버 개발 – 주요 작업 • 서버 구성 • 개발편의상 API 서버와 OAuth 서버는 하나의 서버로 제공 • 회원 정보 관리 • 회원 정보 및 인증 처리는 hard code로 처리 • 개발 환경 • SpringBoot 기반 : Web (API 서버) + Security (OAuth 서버)
  • 19. OAuth 인증 API 서버 개발 – extension 처리 API @RequestMapping(value = "/clova/extension", method= RequestMethod.POST, produces = "application/json" ) @ResponseBody public ResponseEntity<MyExtensionMessage> weather (@RequestBody Map<String, Object> map) { Map m = (HashMap)map.get("request"); String type = (String) m.get("type"); MyExtensionMessage mm = null; if(type.equals("LaunchRequest")) { // extension 시작 mm= new MyExtensionMessage("안녕, 짱구 신사를 시작합니다. 어느 지역 날씨를 알려드릴까요 ?", false); } else if (type.equals("IntentRequest")) { // extension의 인텐트 시작 …........... } else if (type.equals(”SessionEndedRequest")) { // extension 종료 mm= new MyExtensionMessage("짱구 날씨를 종료합니다.", true); } return new ResponseEntity<MyExtensionMessage>(mm, HttpStatus.OK); }
  • 20. OAuth 인증 API 서버 개발 – extension 처리 API if (intentName.equals("weatherIntent")) { if (slots != null) { Map myslot = (HashMap) slots.get("areaSlot"); if(myslot != null ) { slotName = (String) myslot.get("name"); slotValue = (String) myslot.get("value"); System.out.println("slotName===" + slotName); System.out.println("slotValue===" + slotValue); } else { // slot 이 없으면 사용자 정보에서 // 접근토큰을 이용해 사용자의 지역 정보 조회 slotValue = getUserArea(accessToken); } } else { slotValue = getUserArea(accessToken); } mm = new MyExtensionMessage(intentName, slotValue + "의 날씨는 점점 따뜻해 지고 있어요.", false, "PlainText"); // Built-in Intent 처리 } else if (intentName.equals("Clova.YesIntent")) { mm = new MyExtensionMessage(intentName, "예 라고 하셨나요?", true, "PlainText"); } else if (intentName.equals("Clova.NoIntent")) { mm = new MyExtensionMessage(intentName, "노 라고 하셨나요?", true, "PlainText"); } else if (intentName.equals("Clova.GuideIntent")) { mm = new MyExtensionMessage("hearTestIntent", "진주 날씨는 어때라고 해보세요", false, "PlainText"); } else if (intentName.equals("Clova.CancelIntent")) { mm = new MyExtensionMessage("hearTestIntent", "짱구 신사 실행을 취소합니다. 안녕", true, "PlainText"); }
  • 21. Extension 응답 message 처리 클래스 public class MyExtensionMessage { public String version = "1.0"; public Map<String, Object> sessionAttributes = new HashMap(); public MyResponse response = null; public MyExtensionMessage(String message, boolean session) { MyResponseValue value = new MyResponseValue(); value.value = message; if(!session) { sessionAttributes.put("intent", "zzanguWeather"); } MyResponse response = new MyResponse(); response.shouldEndSession = session; response.outputSpeech.put("type", "SimpleSpeech"); response.outputSpeech.put("values", value); this.response = response; } public static class MyResponse { public Map<String, Object> outputSpeech = new HashMap<String, Object>(); public Map<String, Map> card = new HashMap<String, Map>(); public ArrayList<String> directives = new ArrayList<String>(); public boolean shouldEndSession = false; } public static class MyResponseValue { public String type = "PlainText"; public String lang = "ko"; public String value; } }
  • 22. OAuth 인증 API 서버 개발 – 인증 처리 API // 로그인 화면 html 로딩 @GetMapping("/clova/login") @ResponseBody public ModelAndView loginForm(HttpServletResponse httpServletResponse, @RequestParam("state") String state ) { STATE_STRING = state; return new ModelAndView("redirect:" + "/login.html"); } @GetMapping("/clova/config") @ResponseBody public ModelAndView config( ) { return new ModelAndView("redirect:" + "/config.html"); } // login.html 에서 로그인 버튼 클릭시 접근토큰 발급 처리 (id, pw가 맞다고 가정 ) @PostMapping("/clova/login/check") @ResponseBody public void loginCheck(HttpServletResponse httpServletResponse, @RequestParam("userid") String userid, @RequestParam("passwd") String passwd, @RequestParam("state") String state) throws IOException { String redirect_uri = "https://prod-ni-cic.clova.ai/v1/al/token"; String url = "http://user:test@okgosu.net/oauth/authorize?response_type=code&client_id=clova&redirect_uri=" + redirect_uri + "&scope=read&state="+STATE_STRING; httpServletResponse.sendRedirect(url); }
  • 23. OAuth 인증 API 서버 개발 – 회원 API @RequestMapping(value = "/clova/member", method= RequestMethod.POST, produces = "application/json" ) @ResponseStatus(HttpStatus.CREATED) Member create(@RequestBody Member member) { return service.create(member); } @RequestMapping(value = "/clova/member", method= RequestMethod.GET,produces = "application/json" ) Collection<Member> readList() { return service.findAll(); } @RequestMapping(value = "/clova/member/{id}", method= RequestMethod.GET, produces = "application/json" ) ResponseEntity<Member> read(@PathVariable Integer id) { Member b = service.findById(id); return new ResponseEntity<Member>(b, HttpStatus.OK); }
  • 24. OAuth 인증 API 서버 개발 – 회원 관리 등록 @Service public class MemberService { private ConcurrentMap<Integer, Member> repo = new ConcurrentHashMap<>(); private AtomicInteger maxId = new AtomicInteger(0); public MemberService() { Member member = new Member("okgosu", "안드로메다"); Integer id = maxId.addAndGet(1); member.setId(id); repo.put(id, member); } public Member findById(Integer id) { Member b = repo.get(id); return b; } public boolean update(Member member) { Member old = repo.put(member.getId(), member); return old != null; } public Member create(Member member) { Integer id = maxId.addAndGet(1); member.setId(id); repo.put(id, member); return member; } public boolean delete(Integer id) { Member old = repo.remove(id); return old != null; } public Collection<Member> findAll() { return repo.values(); } }
  • 25. Spring Security 설정 @EnableResourceServer @EnableAuthorizationServer @SpringBootApplication public class DemoApplication extends ResourceServerConfigurerAdapter { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/").permitAll() .antMatchers("/clova/member").authenticated(); } } # application.properties security.user.name=user security.user.password=test # client id, secret security.oauth2.client.client-id=clova security.oauth2.client.client-secret=clova123 security.enable-csrf=false security.oauth2.client.scope=read server.port=80
  • 27. Appendix. • Clova Platform 발표자료 : /clovaplatform • Clova 플랫폼 개발자 문서 : https://developers.naver.com/console/clova/guide/ • Design 챕터 / Clova Extensions Kit 챕터 / Clova Developer Console 챕터 참고 • 튜토리얼 및 샘플 코드 참고 • 샘플 코드 Github • 마법 구슬 : https://github.com/naver/clova-extension-sample-magicball • 빗소리 : https://github.com/naver/clova-extension-sample-rainsound • 주사위 놀이 : https://github.com/naver/clova-extension-sample-dice • 코인 헬퍼 : https://github.com/naver/clova-extension-sample-coinhelper