symfony advent calendar day six: security and form validation
์ง๋ ์ค๊ฑฐ๋ฆฌ
5์ผ์งธ ์๋ ํ ํ๋ฆฟ๊ณผ ์ก์ ๋ค์ ๊ฑด๋๋ ค๋ณด์์ต๋๋ค. ํผ๊ณผ ํ์ด์ ์ ๊ดํด์๋ ๋น ์ญํ๊ฒ ์๊ฒ ๋์ จ์ ๊ฒ์ ๋๋ค. ์ค๋ ํ๊ฒ ๋ ๋ถ๋ถ์ ๋ก๊ทธ์ธ๋์ง ์์๊ฑฐ๋ ์น์ธ๋์ง ์์ ์ฌ์ฉ์๊ฐ ํน์ ํ์ด์ง๋ฅผ ์ ๊ทผํ๋ ๊ฒ์ ๋ง๋๋ก ํ๊ฒ ์ต๋๋ค. ์ด ๊ณผ์ ์์ ํผ ๊ฐ์ ํ์ธํ๋ ๊ฒ๋ ํจ๊ป ์ดํด๋ณผ ๊ณํ์ ๋๋ค. ์ด ๊ณผ์ ์์ ์ฌ์ฉ์ ํด๋์ค๊ฐ ์ฌ์ฉ๋ ๊ฒ์ด๋, ์ด์ ๋ํด ์์ง ์ ๋ชจ๋ฅด์ ๋ค๋ฉด ์จ๋ผ์ธ ๋ฌธ์์ค ์ฌ์ฉ์ ํ์ฅ ๋ถ๋ถ ์ ์ดํด๋ณด์๊ธฐ ๋ฐ๋๋๋ค.
๋ก๊ทธ์ธ ํผ๊ฐ ํ์ธํ๊ธฐ (Validation)
๊ฒ์ฆ (Validation) ํ์ผ
๋ก๊ทธ์ธ ํผ์๋ nickname
๊ณผ password
๋ฅผ ์
๋ ฅํ ์ ์๋๋ก ๋์ด ์์ต๋๋ค. ํ์ง๋ง ๋ง์ฝ ์ฌ์ฉ์๊ฐ ๋ถ์ ํํ ์ ๋ณด๋ฅผ ์
๋ ฅํ๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น์? ์ด๋ฌํ ๊ฒฝ์ฐ์ ๋์ฒํ๊ธฐ ์ํด์ ์ฌํฌ๋๋ ํผ๊ฐ ํ์ธ ์์คํ
์ด ์์ต๋๋ค. /fronted/modules/user/validate
๋๋ ํ ๋ฆฌ์ login.yml
ํ์ผ์ ์์ฑํ์ฌ ์๋ ๋ด์ฉ์ ์
๋ ฅํฉ๋๋ค.
methods: post: [nickname, password] names: nickname: required: true required_msg: your nickname is required validators: nicknameValidator password: required: true required_msg: your password is required nicknameValidator: class: sfStringValidator param: min: 5 min_error: nickname must be 5 or more characters
๋จผ์ methods
์๋๋ก ๊ฒํ ํด์ผํ ํ๋๋ค์ ํผ์ด ์ ์ก๋ ๋ฉ์๋์ ํจ๊ป ์ ์ต๋๋ค (POST ๋ฉ์๋๋ง ์ฌ์ฉํ๋ ์ด์ ๋ GET ๋ฉ์๋๋ก ๋์ด์จ ๊ฐ๋ค์ ๋ก๊ทธ์ธ ํผ์ ํ์ํ๊ธฐ ์ํด ์ ๋ฌ๋ ๊ฐ๋ค์ด๊ธฐ ๋๋ฌธ์ ๊ฒํ ํ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์
๋๋ค). ๊ทธ๋ฆฌ๊ณ names
์๋๋ก ๊ฐ๊ฐ์ ํ๋๊ฐ ๊ฐ์ ธ์ผ ํ๋ ๊ฐ๋ค์ ์๋ฌ๋ฉ์์ง์ ํจ๊ป ์
๋ ฅํฉ๋๋ค. ๋ง์ง๋ง์ผ๋ก๋ 'nickname' ํ๋๊ฐ ๊ฐ์ ธ์ผ ํ๋ ๊ฐ์ ๋ํ ๊ท์น์ ์ ํด์ง ํ๋๋ฅผ ์ฌ์ฉํด ์ ์ํฉ๋๋ค. ์ด ์์ ์์๋ ์ฌํฌ๋๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ๊ณตํ๋ sfStringValidator
๋ฅผ ์ฌ์ฉํ์ฌ ๋ฌธ์์ด์ ํํ๋ฅผ ๊ฒ์ฌํฉ๋๋ค (์ฌํฌ๋์ ํผ ๊ธฐ๋ณธ ๊ฒํ ๊ท์น๋ค์ ์๊ณ ์ถ์ผ์๋ค๋ฉด ์จ๋ผ์ธ ๋ฌธ์์ค ํผ๊ฐ ํ์ธํ๊ธฐ ๋ถ๋ถ ์ ์ฐธ๊ณ ํ์๊ธฐ ๋ฐ๋๋๋ค.
์๋ฌ ์ฒ๋ฆฌ
์ ๊ทธ๋ผ ์ฌ์ฉ์๊ฐ ์๋ชป๋ ๋ฐ์ดํฐ๋ฅผ ์
๋ ฅํ ๊ฒฝ์ฐ ์ด๋ป๊ฒ ๋๋์? login.yml
ํ์ผ์ ์ฐ์ฌ์ง ์กฐ๊ฑด์ด ๋ง์กฑ๋์ง ์์ ๊ฒฝ์ฐ์ ์ปจํธ๋กค๋ฌ๋ ์๋ ํธ์ถํ๋๋ก๋ userAction
ํด๋์ค์ executeLogin()
๋ฉ์๋ ๋์ ์ userAction
ํด๋์ค์ handleErrorLogin()
๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค. ๋ง์ฝ ํด๋น ๋ฉ์๋๊ฐ ์กด์ฌํ์ง ์๋๋ค๋ฉด ๊ธฐ๋ณธ์ ์ผ๋ก loginError.php
๋ฅผ ์ถ๋ ฅํฉ๋๋ค. ์ฌ์ค ๊ทธ๊ฒ ๊ธฐ๋ณธ handleError()
๋ฉ์๋๊ฐ ํ๋์ผ์
๋๋ค.
public function handleError() { return sfView::ERROR; }
๊ทธ๋ผ ์๋ก์ด ํ
ํ๋ฆฟ์ ์์ฑํด์ผ ํ๋ ๊ฑด๊ฐ์? ์๋ฌ ํ์ด์ง๋ฅผ ์์ฑํ๋ ๋์ ์, ์๋ฌ ๋ฉ์์ง๋ฅผ ๋ฌธ์ ๊ฐ ์๊ธด ํผ ์์ ์ถ๋ ฅํ๊ณ ๋ก๊ทธ์ธ ํผ์ ๋ค์ ๋ณด์ฌ์ฃผ๋๋ก ํ ๊ฒ์
๋๋ค. ๊ทธ๋ผ ์๋ฌ๊ฐ ๋ฐ์ํ์๋์ ๋์ฒ๋ฐฉ์์ ์์ ํ๊ณ ๋ก๊ทธ์ธ ํ
ํ๋ฆฟ์ธ loginSuccess.php
ํ
ํ๋ฆฟ์ ์์ ํ๋๋ก ํ๊ฒ ์ต๋๋ค.
public function handleErrorLogin() { return sfView::SUCCESS; }
์ฐธ๊ณ : ์ก์ ์ด๋ฆ๊ณผ ๊ทธ๊ฒ์
return
๊ฐ, ๊ทธ๋ฆฌ๊ณ ํ ํ๋ฆฟ ํ์ผ๊ณผ ๊ด๊ณ๋ ์ด๋ฆ ๊ท์ฝ์ ์จ๋ผ์ธ ๋ฌธ์์ค ๋ทฐ ๋ถ๋ถ ์์ ๋ค๋ฃจ๊ณ ์์ต๋๋ค.
ํ ํ๋ฆฟ ์๋ฌ ํฌํผ๋ค
์ด์ loginSuccess.php
๊ฐ ๋ค์ ํธ์ถ๋๋๋ก ํ์์ผ๋ ํ
ํ๋ฆฟ์ ์๋ฌ๋ฅผ ์ถ๋ ฅํ๋๋ก ํ๊ฒ ์ต๋๋ค. Validation
ํฌํผ ๋ชจ์์ form_error()
ํฌํผ๋ฅผ ์ฌ์ฉํ ๊ฒ์
๋๋ค. ๋๊ฐ์ form-row
๋ถ๋ถ์ ์๋์ ๊ฐ์ด ์์ ํฉ๋๋ค.
<?php use_helper('Validation') ?> <div class="form-row"> <?php echo form_error('nickname') ?> <label for="nickname">nickname:</label> <?php echo input_tag('nickname', $sf_params->get('nickname')) ?> </div> <div class="form-row"> <?php echo form_error('password') ?> <label for="password">password:</label> <?php echo input_password_tag('password') ?> </div>
form_error()
ํฌํผ๋ ์ธ์๋ก ๋ฐ์ ๊ฐ์ ํด๋นํ๋ ํ๋์ ์๋ฌ๊ฐ ๋ฐ์๋์์๋, login.yml
์ ์ ์๋ ์๋ฌ ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ ๊ฒ์
๋๋ค.
์ฌ์ฉ์ ์ด๋ฆ์ 5๊ธ์๋ณด๋ค ์งง๊ฒ ์ ๋ ฅํ๊ฑฐ๋ ๋ ์ค์ ์๋ฌด๊ฒ์ด๋ ๋น ์นธ์ผ๋ก ๋จ๊ฒจ๋์ฑ ํ์ธ๋ฒํผ์ ๋๋ฌ์ ํผ๊ฐ ํ์ธ์ด ์ ์๋ํ๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์๋ฌ ๋ฉ์ธ์ง๊ฐ ๋ง์ ์ฒ๋ผ ๊ด๊ณ๋ ํ๋์ ๋ํ๋๋ ๊ฒ์ ํ์ธํ์ค ์ ์์ผ์ค ๊ฒ์ ๋๋ค.
์ด์ ๋น๋ฐ๋ฒํธ๊ฐ ํ์ํญ๋ชฉ์ด ๋์์ต๋๋ค๋ง, ์์ง ์๋ฌด๋ฐ ๋น๋ฐ๋ฒํธ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋์ด ์์ง ์์ต๋๋ค. ์ฌ์ค ์๋ฌด ๋น๋ฐ๋ฒํธ๋ ์ ๋ ฅํ๋๋ผ๋ ๋ก๊ทธ์ธ์ด ๋ ๊ฒ์ ๋๋ค. ์๋นํ ์ข์ ๋ณด์์ฒด๊ณ์ด์ฃ ?
์๋ฌ ๋ฉ์ธ์ง ์คํ์ผ ์ ์
์์์ ํผ์ ํ
์คํธํ์ค๋ ์ ํฌ๊ฐ ์บก์ถฐํ ์ด๋ฏธ์ง์๋ ๋ค๋ฅด๊ฒ ๋ํ๋๋๊ฒ์ ๋ณด์
จ์ ๊ฒ์
๋๋ค. ๊ทธ๊ฒ์ ์ฐ๋ฆฌ๊ฐ web/main.css
์ ์๋ .form_error
์คํ์ผ ํด๋์ค๋ฅผ ์ ์ํ์๊ธฐ ๋๋ฌธ์
๋๋ค. form_error()
ํฌํผ๊ฐ ์๋ฌ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ ๋๋ ๊ธฐ๋ณธ์ ์ผ๋ก .form_error
์คํ์ผ์ด ์ฌ์ฉ๋ฉ๋๋ค. ์๋์ ๊ฐ์ด ํด๋น ์คํ์ผ์ ์ ์ํ๋ฉด ์บก์ถฐํ ์ด๋ฏธ์ง์ ๋์ผํ ์คํ์ผ์ ํ์ธํ์ค ์ ์์ผ์ค ๊ฒ์
๋๋ค.
.form_error { padding-left: 85px; color: #d8732f; }
์ฌ์ฉ์ ์ธ์ฆํ๊ธฐ
์ฌ์ฉ์ ํผ๊ฐ ํ์ธ ๊ท์น
์ด์ ์ฐ๋ฆฌ๋ login
์ก์
์์ ์ฌ์ฉ์์ด๋ฆ์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์กด์ฌํ๋์ง๋ฅผ ํ์ธํ๋๋ก ์ฝ๋๋ฅผ ์์ฑํ์ต๋๋ค. ์ด ์์
๋ ํผ๊ฐ ํ์ธ ๋ถ๋ถ์์ ํ๋๊ฒ์ด ๋ง์ ๊ฒ ๊ฐ์ต๋๋ค. ์ด์ ๊ทธ ์ฝ๋๋ฅผ ์ก์
ํ์ผ์์ ๋ค์ด๋ด๊ณ ์ฌ์ฉ์ ํผ๊ฐ ํ์ธ ๊ท์น์ ์์ฑํ์ฌ ๊ทธ์ชฝ์ผ๋ก ๋ณด๋ด๋๋ก ํ๊ฒ ์ต๋๋ค. ๋ณต์กํด ๋ณด์ด์ ๋ค๊ณ ์? ์ฌ์ค์ ๊ทธ๋ ์ง๋ง๋ ์์ต๋๋ค. login.yml
ํ์ผ์ ์ด๊ณ ์๋์ ๊ฐ์ด ์์ ํฉ๋๋ค.
... names: nickname: required: true required_msg: your nickname is required validators: [nicknameValidator, userValidator] ... userValidator: class: myLoginValidator param: password: password login_error: this account does not exist or you entered a wrong password
nickname
ํ๋์ myLoginValidator
๋ผ๋ ์๋ก์ด ํผ๊ฐ ํ์ธ ๊ท์น์ ์ถ๊ฐํ์์ต๋๋ค. ์ด ๊ท์น์ด ์์ง์ ์กด์ฌํ์ง ์์ต๋๋ค๋ง, ์ฌ์ฉ์๋ฅผ ์ธ์ฆํ๊ธฐ ์ํด์๋ ๋น๋ฐ๋ฒํธ๊ฐ ํ์ํ๊ธฐ๋๋ฌธ์, password
๋ผ๋ ์ด๋ฆ์ผ๋ก ๋น๋ฐ๋ฒํธ๋ฅผ ์ ๋ฌํฉ๋๋ค.
๋น๋ฐ๋ฒํธ ์ ์ฅ
์ ์๋ง์. ์ฐ๋ฆฌ ๋ฐ์ดํฐ ๋ชจ๋ธ๊ณผ ํ ์คํธ ๋ฐ์ดํฐ์๋ ๋น๋ฐ๋ฒํธ๊ฐ ์์ง ์์ต๋๋ค. ๋จผ์ ์ฌ์ฉ์๋ค์ ๋น๋ฐ๋ฒํธ๋ฅผ ์ ์ฅํ๋๋ก ํ๊ฒ ์ต๋๋ค. ํ์ง๋ง ์์๋ค์ํผ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ผ๋ฐ ํ๋ฌธ์ผ๋ก ์ ์ฅํ๋ ๊ฒ์ ๋ณด์์ ์ข์ง ์๊ธฐ ๋๋ฌธ์, ์ฐ๋ฆฌ๋ ๋น๋ฐ๋ฒํธ๋ฅผ ๋๋ค ํค๋ก sha1 ํด์ฌ ํ์ฌ ์ ์ฅํ๋๋ก ํ๊ฒ ์ต๋๋ค. ๋ง์ฝ ์ด '์๊ธ' (์ฃผ - ๋น๋ฐ๋ฒํธ์ ๋ํ๋ ๋๋คํค๋ฅผ 'salt' ๋ผ๊ณ ํฉ๋๋ค) ๋ฐฉ์์ด ์ต์ํ์ง ์๋ค๋ฉด ๋น๋ฐ๋ฒํธ ๊นจํธ๋ฆฌ๊ธฐ ์ค๋ก ๋ฅผ ํ ๋ฒ ๋ณด์๊ธฐ ๋ฐ๋๋๋ค.
schema.xml
ํ์ผ์ ์ฌ์๊ณ User
ํ
์ด๋ธ์ ๋ค์์ ์ถ๊ฐํฉ๋๋ค.
<column name="email" type="varchar" size="100" /> <column name="sha1_password" type="varchar" size="40" /> <column name="salt" type="varchar" size="32" />
symfony propel-build-model
์ ์คํํ์
์ ๋ชจ๋ธ์ ์๋ก ์์ฑํฉ๋๋ค. symfony propel-build-sql
๋ช
๋ น์ ํตํด์ ์์ฑํ lib.model.schema.sql
์ ์ฌ์ฉํ๋์ง ์ง์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ํ์
์ ํ์๋์ง, ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ด ํ๋๋ค์ ์ถ๊ฐํ์ฌ์ผ ํฉ๋๋ค. ์ด์ askeet/lib/model/User.php
ํ์ผ์ ์ด๊ณ setPassword()
๋ฉ์๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
public function setPassword($password) { $salt = md5(rand(100000, 999999).$this->getNickname().$this->getEmail()); $this->setSalt($salt); $this->setSha1Password(sha1($salt.$password)); }
์ผ๋ฐ์ ์ธ ๋น๋ฐ๋ฒํธ ์ ์ฅ๋ฐฉ์๊ณผ ๋ค๋ฅผ๋ฐ์์ด๋ณด์ด์ง๋ง, ์ ๋ฐฉ์์ผ๋ก ์์์ ์๊ธ
(32๊ธ์ ํด์ฌ๋ ์์์ ๋ฌธ์์ด) ๊ณผ ํด์ฌ๋ ๋น๋ฐ๋ฒํธ (40 ๊ธ์ ๋ฌธ์์ด) ๋ฅผ ์ ์ฅํฉ๋๋ค.
ํ ์คํธ ๋ฐ์ดํฐ์ ๋น๋ฐ๋ฒํธ ์ถ๊ฐ
3์ผ์งธ ์ ๋ง๋ค์๋ ๋ฐ์ดํฐ ํ์ผ ๊ธฐ์ต๋์๋์? ๋น๋ฐ๋ฒํธ์ ์ด๋ฉ์ผ์ ํ
์คํธ ๋ฐ์ดํฐ์ ์ถ๊ฐํฉ๋๋ค. askeet/data/fixtures/test_data.yml
ํ์ผ์ ์ด๊ณ ์๋์ ๊ฐ์ด ์์ ํฉ๋๋ค.
User: ... fabien: nickname: fabpot first_name: Fabien last_name: Potencier password: symfony email: fp@example.com francois: nickname: francoisz first_name: Franรงois last_name: Zaninotto password: adventcal email: fz@example.com
User
ํด๋์ค์ setPassword()
๋ฉ์๋๊ฐ ์ด๋ฏธ ์ ์๋์ด ์์ผ๋ฏ๋ก, sfPropelData
๊ฐ์ฒด๋ sha1_password
์ salt
์ปฌ๋ผ์ ์๋์ผ๋ก ์์ฑํ์ฌ ์ค ๊ฒ์
๋๋ค. ์ด์ ์๋ ๋ช
๋ น์ ํธ์ถํฉ๋๋ค.
$ php batch/load_data.php
์ฐธ๊ณ :
sfPropelData
๊ฐ์ฒด๋์ค์
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ปฌ๋ผ์ ๊ธฐ๋ฐํ์ฌ ์์ฑ๋ ๋ฉ์๋๊ฐ ์๋๋๋ผ๋ ์ฌ์ฉ์ด ๊ฐ๋ฅํฉ๋๋ค.์ด์ ๋ํ ์ข ๋ ์์ธํ ๋ด์ฉ์ ์จ๋ผ์ธ ๋ฌธ์์ค ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๋ฃ ์ ๋ ฅํ๊ธฐ ๋ถ๋ถ ์ ์ฐธ์กฐํ์๊ธฐ ๋ฐ๋๋๋ค.
์ฐธ๊ณ : 'Anonymous Coward' ์ฌ์ฉ์์ ๋ํด์ ๋น๋ฐ๋ฒํธ๋ฅผ ์ง์ ํ ํ์๋ ์์ต๋๋ค. ์ฐ๋ฆฌ๋ ํด๋น ์ฌ์ฉ์๋ฅผ ๋ก๊ทธ์ธํ์ง ๋ชป ํ๋๋ก ํ ๊ณํ์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ ๋น๋ฐ๋ฒํธ๋ ์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํ๋ ๋น๋ฐ๋ฒํธ๋ค๊ณผ๋ ์ ํ ์ฐ๊ด์ด ์์ผ๋ ํ๊ณ ์ํ์ง ๋ง์๊ธฐ ๋ฐ๋๋๋ค.
์ฌ์ฉ์ ํผ๊ฐ ํ์ธ ๊ท์น
์ด์ myLoginValidator
๋ฅผ ์์ฑํด๋ณด๊ฒ ์ต๋๋ค. ํ์ผ์ ๋ชจ๋์ด ์ ๊ทผ ๊ฐ๋ฅํ askeet/lib/
๋ askeet/aps/frontend/lib/
, ๋๋ askeet/apps/frontend/modules/user/lib/
์ค ์ด๋๊ณณ์ ๋ง๋์
๋ ๋ฌด๋ฐฉํฉ๋๋ค. ์ง๊ธ์ ์ ์ฒด ์ดํ๋ฆฌ์ผ์ด์
์์ ์ด ๊ท์น์ ์ฌ์ฉํ ๊ฒ์ด๋ผ๊ณ ๊ฐ์ ํ๊ณ askeet/apps/frontend/lib/
์๋์ myLoginValidator.class.php
๋ผ๋ ์ด๋ฆ์ผ๋ก ํ์ผ์ ๋ง๋ค๋๋ก ํ๊ฒ ์ต๋๋ค.
<?php class myLoginValidator extends sfValidator { public function initialize($context, $parameters = null) { // initialize parent parent::initialize($context); // set defaults $this->setParameter('login_error', 'Invalid input'); $this->getParameterHolder()->add($parameters); return true; } public function execute(&$value, &$error) { $password_param = $this->getParameter('password'); $password = $this->getContext()->getRequest()->getParameter($password_param); $login = $value; // anonymous is not a real user if ($login == 'anonymous') { $error = $this->getParameter('login_error'); return false; } $c = new Criteria(); $c->add(UserPeer::NICKNAME, $login); $user = UserPeer::doSelectOne($c); // nickname exists? if ($user) { // password is OK? if (sha1($user->getSalt().$password) == $user->getSha1Password()) { $this->getContext()->getUser()->setAuthenticated(true); $this->getContext()->getUser()->addCredential('subscriber'); $this->getContext()->getUser()->setAttribute('subscriber_id', $user->getId(), 'subscriber'); $this->getContext()->getUser()->setAttribute('nickname', $user->getNickname(), 'subscriber'); return true; } } $error = $this->getParameter('login_error'); return false; } }
ํผ๊ฐ ํ์ธ ํด๋์ค (validator) ๊ฐ ์์ ์์ - ์ฌ๊ธฐ์๋ login
ํผ์ด ์ ์ถ๋ ํ๊ฒ ์ง์ - initialize()
๋ฉ์๋๊ฐ ๋จผ์ ํธ์ถ๋ฉ๋๋ค. ํด๋น ๋ฉ์๋๋ login_error
๋ฉ์ธ์ง์ ๊ธฐ๋ณธ๊ฐ์ผ๋ก Invalid Input
์ ์ ์ฅํ๊ณ login.yml
ํ์ผ์ parma:
ํค๋ ์๋ ์๋ ๊ฐ๋ค์ ํ๋ผ๋ฏธํฐ ํ๋ ๊ฐ์ฒด๋ก ๋ณํฉํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ execute()
๋ฉ์๋๊ฐ ํธ์ถ๋ฉ๋๋ค. $password_param
์ login.yml
ํ์ผ์ password
ํค๋ ์๋์ ์๋ ํ๋์ ์ด๋ฆ์
๋๋ค. ์ด ํ๋ ์ด๋ฆ์ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ์์ฒญ๊ฐ๋ค ์ค์์ ๋น๋ฐ๋ฒํธ๋ฅผ ์ฐพ์ต๋๋ค. ๋ฐ๋ผ์ $password
๋ณ์์๋ ์ค์ ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ๋น๋ฐ๋ฒํธ๊ฐ ๋ค์ด๊ฐ๊ฒ ๋ฉ๋๋ค. $value
๋ณ์์๋ ํ์ฌ ํ๋์ ๊ฐ, ์ฆ myLoginValidator
ํด๋์ค๋ nickname
ํ๋๋ฅผ ํ์ธํ๊ธฐ ์ํด ํธ์ถ๋์์ผ๋ฏ๋ก, ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ์ด๋ฆ์ด ๋ค์ด๊ฐ๊ฒ ๋ฉ๋๋ค. ๋๋์ด ํผ๊ฐ ํ์ธ ํด๋์ค๊ฐ ์ฌ์ฉ์๋ฅผ ํ์ธํ๋๋ฐ ํ์๋ก ํ๋ ๋ฐ์ดํฐ๋ค์ด ๋ชจ๋ ๋ชจ์์ต๋๋ค.
์ดํ์ ์ฝ๋๋ค์ login
์ก์
์์ ๋ฐ์จ๊ฒ๋ค์
๋๋ค. ํ์ง๋ง ๋น๋ฐ๋ฒํธ๊ฐ ์ฌ๋ฐ๋ฅธ์ง ํ์ธํ๋ ๋ถ๋ถ์ด ์ถ๊ฐ๋์์ต๋๋ค (์ง๋๋ฒ์๋ ํญ์ ์ฐธ์ด์์ฃ ?). ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ๋น๋ฐ๋ฒํธ๋ฅผ ์ ์ฅ๋์ด ์๋ ์๊ธ๊ฐ๊ณผ ํฉํ์ฌ ํด์ฌํ๊ณ , ์ด๋ฅผ ๊ธฐ์กด์ ํด์ฌ๋ ๋น๋ฐ๋ฒํธ์ ๋น๊ตํฉ๋๋ค.
๋ง์ฝ ๋ก๊ทธ์ธ ์์ด๋์ ๋น๋ฐ๋ฒํธ๊ฐ ์ ํํ๋ค๋ฉด, ํผ๊ฐ ํ์ธ ํด๋์ค๋ ์ฐธ
์ ๋ฐํํ๊ณ ์๋์ ์ก์
์ธ executeLogin()
์ด ์คํ๋ ๊ฒ์
๋๋ค. ๋ง์ฝ ๊ทธ๋ ์ง ์๋ค๋ฉด ๊ฑฐ์ง
์ ๋ฐํํ๊ณ , handleErrorLogin()
๋ฉ์๋๊ฐ ์คํ๋ ๊ฒ์
๋๋ค.
์ก์ ์์ ์ฝ๋ ์ ๊ฑฐํ๊ธฐ
์ ์ด์ ์ฌ์ฉ์๋ฅผ ํ์ธํ๋ ์ฝ๋๋ ํผ๊ฐ ํ์ธ ํด๋์ค๋ก ์ฎ๊ฒจ์ก์ผ๋, ๊ธฐ์กด ์ฝ๋๋ฅผ login
์ก์
์์ ์ ๊ฑฐํ๋๋ก ํ๊ฒ ์ต๋๋ค. ์ก์
์ด POST ๋ฉ์๋๋ก ํธ์ถ๋๋ ๊ฒฝ์ฐ, ์ฌ์ฉ์์ ์์ฒญ์ ํผ๊ฐ ํ์ธ ๋ชจ๋๋ก๋ถํฐ ํผ๊ฐ์ด ์ฌ๋ฐ๋ฅธ์ง ํ์ธ์ ๋ฐ๊ฒ ๋๋ฏ๋ก executeLogin()
๊ฐ ์คํ๋์๋ค๋ฉด, ํด๋น ์ฌ์ฉ์์ ์์ด๋์ ๋น๋ฐ๋ฒํธ๋ ์ ํํ๋ค๊ณ ๋ณผ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ executeLogin()
๋ฉ์๋์์๋ referer
ํ์ด์ง๋ก ์ฌ์ฉ์๋ฅผ ์ด๋์ํค๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค.
public function executeLogin() { if ($this->getRequest()->getMethod() != sfRequest::POST) { // display the form $this->getRequest()->getParameterHolder()->set('referer', $this->getRequest()->getReferer()); return sfView::SUCCESS; } else { // handle the form submission // redirect to last page return $this->redirect($this->getRequestParameter('referer', '@homepage')); } }
ํ ์คํธ ์ฌ์ฉ์์ค ํ๋์ ์ ๋ณด๋ฅผ ์ด์ฉํด์ ๋ก๊ทธ์ธ์ ์๋ํด๋ณด์ญ์์ค (์๋์ผ๋ก ์ ์ฌ๋์ด์ผํ๋ ํผ๊ฐ ํ์ธ ํด๋์ค๊ฐ ์์ฑ๋์๊ธฐ ๋๋ฌธ์, ์คํ์ ์ ์บ์๋ฅผ ์ง์ฐ์ ์ผ ํฉ๋๋ค).
์ด์ฉ ์ ํ
ํน์ ์ก์
์ ๋ํด ์ด์ฉ์ ์ ํํ๊ณ ์ถ์ผ์๋ค๋ฉด ๋ชจ๋์ config/
๋๋ ํ ๋ฆฌ์ security.yml
ํ์ผ์ ์ถ๊ฐํ์
์ ๋ค์๊ณผ ๊ฐ์ด ๋ด์ฉ์ ์ฑ์ฐ์
์ผ ํฉ๋๋ค.
all: is_secure: on credentials: subscriber
์ด๋ ๊ฒ ํ ๊ฒฝ์ฐ ํด๋น ๋ชจ๋์ ์ฌ์ฉ์๊ฐ ์ธ์ฆ๋ ์ฌ์ฉ์์ด๊ณ subscriber
๋ผ๋ ์ฆ๋ช
๊ฐ (credential) ์ ๊ฐ์ง๊ณ ์๋ ๊ฒฝ์ฐ์ ํํด ์ด์ฉํ ์ ์๊ฒ๋ฉ๋๋ค.
askeet ์์๋ ์๋ก์ด ์ง๋ฌธ์ ํ๊ฑฐ๋, ์ง๋ฌธ์ ๋ํ ํฅ๋ฏธ๋๋ฅผ ์ถ๊ฐํ๊ฑฐ๋, ๋๋ ๋ต๋ณ์ ์ ์๋ฅผ ๋งค๊ธธ๋์๋ง ๋ก๊ทธ์ธ์ด ํ์ํ๋๋ก ํ ๊ฒ์ ๋๋ค. ๊ทธ ์ธ์ ๋ค๋ฅธ ๋ชจ๋ ์ก์ ์ ๋ก๊ทธ์ธ๋ ์ฌ์ฉ์๊ฐ ์๋์ด๋ ์ด์ฉ์ด ๊ฐ๋ฅํ ๊ฒ์ ๋๋ค.
์๋ฅผ๋ค์ด, question/add
์ก์
์ ๋ํด์ (์์ง ์์ฑ๋์ง ์์์ง๋ง) ์ด์ฉ์ ์ ํํ๊ณ ์ถ๋ค๋ฉด, askeet/apps/frontend/modules/question/config/
๋๋ ํ ๋ฆฌ์ security.yml
ํ์ผ์ ๋ค์๊ณผ ๊ฐ์ด ๋ง๋ค๋ฉด ๋ฉ๋๋ค.
add: is_secure: on credentials: subscriber all: is_secure: off
๋ฆฌํํ ๋ง ํํ?
์ ๋ง์ง๋ง์ผ๋ก ๋๋ด๊ธฐ ์ ์, ์ฐ๋ฆฌ๊ฐ ๊ฐ์ฅ ์ข์ํ๋ ์ฝ๋๋ฅผ์ฌ๋ฐ๋ฅธ๊ณณ์์ฎ๊ธฐ๊ธฐ ๊ฒ์์ ํ ํ ํ๋๋ก ํ์ฃ .
๋น๋ฐ๋ฒํธ๋ฅผ ํ์ธํ๊ณ ์ฌ์ฉ์๊ฐ ํ์ธ๋์์๋, ์ฌ์ฉ์์ ๊ถํ์ ์ฆ๋ช
ํ๊ณ ๋์ค์ ์ํด ์ฌ์ฉ์์ id
๋ฅผ ์ ์ฅํ๋ ๋ค์ค์ ์ฝ๋๊ฐ ์์ต๋๋ค. ์ด ์ฝ๋๋ค์ myUser
ํด๋์ค (๋ฐ์ดํฐ๋ฒ ์ด์ค์ User
์ ๋ํ ํด๋์ค๊ฐ ์๋๋ผ ์ธ์
์ ๊ดํ ํด๋์ค) ์ ๋ฉ์๋๋ก ๋ง๋ค ์ ์์ต๋๋ค. askeet/apps/frontend/lib/myUser.php
ํด๋์ค์ ๋ค์ ๋ฉ์๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
public function signIn($user) { $this->setAttribute('subscriber_id', $user->getId(), 'subscriber'); $this->setAuthenticated(true); $this->addCredential('subscriber'); $this->setAttribute('nickname', $user->getNickname(), 'subscriber'); } public function signOut() { $this->getAttributeHolder()->removeNamespace('subscriber'); $this->setAuthenticated(false); $this->clearCredentials(); }
์ด์ myLoginValidator
ํด๋์ค์ $this->getContext()->getUser()
๋ก ์์ํ๋ ๋ค ์ค์ ์๋์ ๊ฐ์ด ์์ ํฉ๋๋ค.
$this->getContext()->getUser()->signIn($user);
user/logout
์ก์
์ญ์ (์์ผ์ ๊ฑด ์๋์ฃ ?) ์๋์ ๊ฐ์ด ์์ ํฉ๋๋ค.
public function executeLogout() { $this->getUser()->signOut(); $this->redirect('@homepage'); }
subscriber_id
์ nickname
์ธ์
๊ฐ๋ค ์ญ์ ๊ฒํฐ ๋ฉ์๋๋ก ์ถ์ํ๋ ์ ์์ ๊ฒ์
๋๋ค. myUser
ํด๋์ค์ ๋ค์ ์ธ ๋ฉ์๋๋ค์ ์ถ๊ฐํฉ๋๋ค.
public function getSubscriberId() { return $this->getAttribute('subscriber_id', '', 'subscriber'); } public function getSubscriber() { return UserPeer::retrieveByPk($this->getSubscriberId()); } public function getNickname() { return $this->getAttribute('nickname', '', 'subscriber'); }
layout.php
์์๋ ์๋ก์ด ๋ฉ์๋๋ค์ ์ฌ์ฉํ๋๋ก ํ๊ฒ ์ต๋๋ค. ์๋ ์ฝ๋๋ฅผ
<li><?php echo link_to($sf_user->getAttribute('nickname', '', 'subscriber').' profile', 'user/profile') ?></li>
์๋์ ๊ฐ์ด ๋ฐ๊พธ์ญ์์ค.
<li><?php echo link_to($sf_user->getNickname().' profile', 'user/profile') ?></li>
์์ ์ฌํญ์ ํ ์คํธํ๋ ๊ฒ์ ์์ง ๋ง์ญ์์ค. ์ด์ ๊ณผ ๋ก๊ทธ์ธ ํ๋ก์ธ์ค๊ฐ ๋์ผํ๊ฒ ์ฒ๋ฆฌ๋์ด์ผ ํฉ๋๋ค (ํ์ง๋ง ์ฝ๋๋ ํจ์ฌ ๊น๋ํ์ฃ ).
๋ด์ผ ์ด์๊ฐ์
๋ด์ผ์ ๋ทฐ ์ค์ ์ ์ดํด๋ณด๊ณ , CSS ๋ฅผ ์์ ํ๊ณ , ์ผ๊ด๋ (consistent) ์ปดํฌ๋ํธ๋ค๊ณผ๊ณ ํ์ด์ง ํค๋๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์ค๋ ์์ฑ๋ ์ฝ๋๋ค์ askeet SVN ์ ์ฅ์ ์์ release_day_6
ํ๊ทธ๋ก ๋ค์ด๋ก๋ ๊ฐ๋ฅํฉ๋๋ค. askeet ์ ๋ํ ์ง๋ฌธ์ askeet ํฌ๋ผ ์์ ์์ ๋กญ๊ฒ ํด์ฃผ์๊ธฐ ๋ฐ๋๋๋ค. 21์ผ์งธ ๋ฌด์์ ํ ์ง๋ ์ฌ๋ฌ๋ถ์๊ฒ ๋ฌ๋ ค ์๋ค๋ ๊ฒ๋ ์์ง ๋ง์์ฃผ์๊ตฌ์.
This work is licensed under the Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License license.