6. 비밀번호 변경 및 재발급

6.1 비밀번호 변경

이제 기본적으로 회원가입, 로그인, 로그아웃에 대한 기능들은 모두 만들었습니다. 다음은 비밀번호 찾기 및 재발급에 대한 기능을 추가해 보겠습니다.
아래는 비밀번호 변경 html 파일소스입니다. 기존비번, 새비번, 새비번 확인의 3가지 텍스트 박스로 구성된 폼 입니다.

client/change-password.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<template name="changePassword">
<div class="panel panel-default col-md-6 col-md-offset-3 panel-custom">
<div class="panel-heading text_center">
<a href="{{pathFor '/'}}"><h2>METEOR ACCOUNTS</h2></a>
<p>비밀번호 변경</p>
</div>
<div class="panel-body panel-body-set">
<form class="col-md-12 panel-body-inner">
<div class="form-group">
<input type="text" id="old-password" class="form-control account-text-form-1" placeholder="기존 비밀번호">
</div>
<div class="form-group">
<input type="text" id="new-password" class="form-control account-text-form-1" placeholder="새 비밀번호">
</div>
<div class="form-group">
<input type="text" id="new-password-confirm" class="form-control account-text-form-1" placeholder="새 비밀번호 확인">
</div>
</form>
<div class="form-group panel-body-inner bottom-padding">
<button name="change-password" class="btn btn-danger btn-lg btn-block button">비밀번호 변경</button>
</div>
</div>
</div>
</template>

다음은 이 폼이 실제로 실행될 자바스크립트 파일입니다. 지금까지와의 소스와 조금 다른 점이 있다면 패스워드 변경 api인 Accounts.changePassword이 클라이언트 측에서 실행된다는 점입니다. 그래서 폼검증을 서버가 아닌 클라이언트에서 실행시켜 주는 것을 볼 수 있습니다. 이전 강좌에서도 말했듯 lib 폴더의 있는 소스는 클라이언트와 서버 모두에서 사용 가능하다는 것을 다시한번 확인 할 수 있습니다.

client/change-password.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
Template.changePassword.events({
'click button[name=change-password]' (evt, tmpl)
{
evt.preventDefault(); //새로 고침 방지
var oldPassword = tmpl.find('#old-password').value;
var newPassword = tmpl.find('#new-password').value;
var newPasswordConfirm = tmpl.find('#new-password-confirm').value;
try
{
NotEmptyString(oldPassword);
NotEmptyString(newPassword);
NotEmptyString(newPasswordConfirm);
isValidPassword(newPassword);
isMatchPassword(newPassword, newPasswordConfirm);
}
catch(err)
{
Bert.alert( err.message , 'danger', 'growl-top-right' );
return;
}
Accounts.changePassword(oldPassword, newPassword, function(err)
{
if(!err)
{
Bert.alert('패스워드를 변경했습니다.' , 'success', 'growl-top-right');
}
else
{
console.log(err);
var errMessage = '';
if(err.message === 'Incorrect password [403]')
{
errMessage = "기존 비밀번호가 다릅니다."
}
else
{
errMessage = err.message;
}
Bert.alert( errMessage , 'danger', 'growl-top-right' );
}
});
}
});

Meteor API는 그 성격에 따라 클라이언트, 서버 모두에서 실행되기도 하고, 각각에서만 실행되는 경우도 있습니다. 아래 링크에는 각 API가 어떤 곳에서 실행되는지 잘 정리되어 있습니다. 가끔 왜 이곳에서 실행이 안되지 할 때 확인해 보시면 도움을 받을 수 있습니다.

http://frozeman.de/blog/2015/01/meteor-cheatsheet/


6.2 비밀번호 재발급(잊어버렸을 때)

비밀번호 변경과 함께 자주 쓰게 될 기능은 비밀번호 재발급이 될 것입니다. 비슷한 기능 같지만, 재발급의 경우 비밀번호를 잊어버렸을 경우에 사용되는 기능입니다.
재발급 과정을 설명드리겠습니다.

재발급 과정 : 재발급 페이지(가입 이메일 입력) -> 가입 이메일 페이지에서 링크 확인 -> 재발급 페이지에서 비밀번호 변경

  1. 재발급 페이지

  1. 가입 메일에서 재발급 페이지 링크 확인

  1. 재발급 페이지에서 비밀번호 변경

자 먼저 라우터를 추가해 보도록 하겠습니다. recover는 기본적인 재발급 페이지에 대한 주소가 되고, reset-password는 메일로 보내진 키 값을 확인하는 페이지가 되겠습니다. 키가 맞으면 window.resetPasswordVar라는 reactiveVar를 만들고 여기에 키값을 넣어 주는 식의 구조가 되겠습니다.

lib/routes.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.
.
.
[위 생략]
// 비밀번호 변경 관련
FlowRouter.route('/ recover', {
name:'recoverPassword',
action: function()
{
BlazeLayout.render('mainLayout', {
content: 'recoverPassword'
});
}
});
FlowRouter.route( '/reset-password/:token', {
name: 'reset-password/',
action( params )
{
window.resetPasswordVar = new ReactiveVar(params.token);
FlowRouter.go( '/recover' );
}
});

두번째로 패스워드 재발급의 경우도 메일을 통해서 이루어지므로 가입확인 메일과 다른 재발급 키 값에 대한 메일을 보내는 부분을 세팅하도록 하겠습니다.

server/accountsMails.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 가입확인 메일
Accounts.emailTemplates.verifyEmail = {
.
.
.
[중략]
.
.
.
};
// 비밀번호 변경 메일
Accounts.emailTemplates.resetPassword = {
subject() {
return "Meteor accounts 비밀번호 변경 메일";
},
text( user, url ) {
//let emailAddress = user.emails[0].address,
let emailAddress = user.username,
urlWithoutHash = url.replace( '#/', '' ),
supportEmail = "이메일 주소",
emailBody = `비밀번호 변경 을 원하시면 다음 링크를 클릭해주세요. \n\n link: ${urlWithoutHash} \n\n 만약 확인을 요청하지 않은 경우, 이 이메일을 무시하십시오. 문제가 있다고 생각되면 다음 서비스 지원팀에 문의하십시오. \n\n 문의 주소 : ${supportEmail}.`;
console.log('mailUser');
console.log(user);
return emailBody;
}
};

다음으로 recover-password.html 를 작성해 보도록 하겠습니다 소스에서 특별한 점은 #if resetPassword ...else 이 부분이 되겠는데요. 이메일로 보내진 키값을 확인해 reactiveVar로 넘겨진 resetPasswordVar 를 체크하여 값이 없으면 메일보내기 페이지를 키값이 있으면 새로운 비밀번호 입력 페이지를 보여주는 조건문이라고 보시면 되겠습니다. (reactiveVar의 경우 앞의 강좌에서 조금 설명드렸으니 그부분을 참고 하시면 도움이 될 것 같습니다. 기회가 되면 좀 더 자세히 다룰 만한 주제긴 하네요. 알아두면 참 편리한 기능이라고 생가하는 기능입니다.ㅎ)

client/recover-password.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<template name="recoverPassword">
{{#if resetPassword}}
<div class="panel panel-default col-md-6 col-md-offset-3 panel-custom">
<div class="panel-heading text_center">
<a href="{{pathFor '/'}}"><h2>METEOR ACCOUNTS</h2></a>
<p>비밀번호 변경</p>
</div>
<div class="panel-body panel-body-set">
<form class="col-md-12 panel-body-inner">
<div class="form-group">
<input type="text" id="reset-password" class="form-control account-text-form-1" placeholder="비밀번호">
</div>
<div class="form-group">
<input type="text" id="reset-password-confirm" class="form-control account-text-form-1" placeholder="비밀번호 확인">
</div>
</form>
<div class="form-group panel-body-inner bottom-padding">
<button name="reset-password" class="btn btn-danger btn-lg btn-block button">비밀번호 변경</button>
</div>
</div>
</div>
{{else}}
<div class="panel panel-default col-md-6 col-md-offset-3 panel-custom">
<div class="panel-heading text_center">
<a href="{{pathFor '/'}}"><h2>METEOR ACCOUNTS</h2></a>
<p>비밀번호 변경</p>
</div>
<div class="panel-body panel-body-set">
<form class="col-md-12 panel-body-inner">
<div class="form-group">
<input type="text" id="user-email" class="form-control account-text-form-1" placeholder="메일주소">
</div>
</form>
<div class="form-group panel-body-inner bottom-padding">
<button name="send-email" class="btn btn-danger btn-lg btn-block button">메일보내기</button>
</div>
</div>
</div>
{{/if}}
</template>

위의 html페이지에 대한 js 파일을 작성해 보도록 하겠습니다. 우선 Template.recoverPassword.helpers({}) 에 resetPassword라는 함수를 만들고 라우터에서 세팅된 resetPasswordVar를 get() 하는 소스를 작성해주세요. 이 부분 때문에 html페이지의 #if resetPassword이 작동하게 됩니다.

Accounts.resetPassword(resetPasswordVar.get(), password, function(err){}) 부분은 실제 패스워드를 재발급 하는 소스 입니다. 처음 resetPasswordVar.get() 는 메일로 발송된 키 값에 대한 검증하는 부분이 되겠습니다. 이 발급된 키가 맞다면 새로 입력하는 패스워드로 변경이 이루어 집니다. 보시면 알겠지만, 사용되는 API들이 상당히 꼼꼼하게 만들어 졌다는 것을 볼 수 있습니다.

client/recover-password.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
Template.recoverPassword.onRendered(function () {
showLoadingEffect.set(false);
});
Template.recoverPassword.helpers({
resetPassword: function()
{
//return Session.get('resetPassword');
return resetPasswordVar.get();
Bert.alert( resetPasswordVar.get(), 'success' );
}
});
Template.recoverPassword.events({
'click button[name=reset-password]' (evt, tmpl)
{
evt.preventDefault();
var password = tmpl.find('#reset-password').value;
var passwordAgain = tmpl.find('#reset-password-confirm').value;
// 입력 검증
try
{
NotEmptyString(password);
NotEmptyString(passwordAgain);
isMatchPassword(password, passwordAgain);
}
catch (err)
{
Bert.alert( err.message , 'danger', 'growl-top-right' );
}
// 비밀번호 재발급
Accounts.resetPassword(resetPasswordVar.get(), password, function(err)
{
if(err)
{
Bert.alert( '패스워드 변경중 오류가 발생했습니다.' , 'danger', 'growl-top-right' );
}
else
{
Bert.alert('패스워드를 변경했습니다 ', 'success', 'growl-top-right');
}
});
},
'click button[name=send-email]' (evt, tmpl)
{
evt.preventDefault();
showLoadingEffect.set(true);
var email = tmpl.find('#user-email').value; // trim 대기
Accounts.forgotPassword({email: email}, function(err)
{
if(err)
{
if(err.message == 'User not found [403]')
{
console.log(err.message);
showLoadingEffect.set(false);
Bert.alert( '해당메일로 가입자가 없습니다.' , 'danger', 'growl-top-right' );
}
else
{
showLoadingEffect.set(false);
Bert.alert( '오류로 메일 발송에 실패했습니다. 잠시후 다시 시도해주세요.' , 'danger', 'growl-top-right' );
}
}
else
{
showLoadingEffect.set(false);
Bert.alert( '비밀번호 변경에 관한 메일을 발송했습니다.' , 'success', 'growl-top-right' );
}
});
}
});

이상으로 패스워드 재발급 까지 만들어 봤습니다. 이제 제법 그럴듯한 회원가입 기능이 구현된 것 같은데요. 다음 강좌에서는 마지막으로 각종 소셜 서비스를 통한 가입에 대한 기능을 구현해보도록 하겠습니다. 이제와서 말씀 드리지만 사실상 이 소스는 소셜 로그인 기능을 만들다가 정리된 소스라고 보셔도 됩니다. 매력적이고 많이 쓰이는 기능들이 meteor에서는 참 쉽게 사용할 수 있었던 것 같습니다. 그럼 다음강좌에서 소셜 로그인을 구현해 보는 것으로 Meteor custom account 강좌를 마무리 해보도록 하겠습니다 ^^