본문 바로가기

개발/React & React Native

React. Session처리

이것은 React를 이용 웹서비스 개발 시, 사용자 로그인을 다른 LDAP 서버와 연동해서 처리하는 것에 대한 것이다.


Server Side 프로그래밍 


필요 node 패키지는 authentication을 위한 passport 패키지와 passport 상에서 LDAP 연동을 위한 passport-ldapauth 이다.

npm install --save passport 

npm install --save passport-ldapauth


passport 에 대한 것은 아래 링크 참고.

http://www.passportjs.org/


passport-ldapauth에 대한 것은 아래 링크 참고

https://github.com/vesse/passport-ldapauth


LDAP 서버 접근을 위한 설정을 한다. 각종 설정 Option은 위에 passport-ldapauth 링크에서 확인한다.

연동하고자 하는 LDAP 서버를 위한 구체적인 설정값을 찾기 위해서

Linux 상에 ldap-utils 를 설치해서 command line 명령어인 ldapsearch 를 이용하면 좋다.

참고로 아래 명령어는 ldapsearch로 특정 사용자 kdhong 의 암호가 홍길동암호가 맞는지 확인해보는 명령어 인데,

이것은 LDAP 서버마다 다르니 확인해 봐야 한다.

ldapsearch -h gw.idis.co.kr -D "cn=홍길동" -b O=IDIS uid=kdhong -x -w 홍길동암호


OPTS 옵션 설정값을 셋팅하고 passport에서 LDAP를 사용하도록 한다.

var OPTS = {
    server : {
        url : 'ldap://gw.idis.co.kr:389',
        searchBase : 'O=IDIS',
        searchFilter : '(uid={{username}})',
    }
};
...
passport.use(new Ldap(OPTS));


/login url 에 대한 post message처리에서 middleware로서 passport.authentication('ldapauth') 를 호출하면 req.body.username 과 req.body.password 에 계정 정보를 이용해서 LDAP 서버에 인증을 시도한다. 인증이 성공하면 passport.serializeUser 함수가 호출되고 session.passport.user 필드에 user정보가 기록된다. 이후 아무 page가 loading될 때 마다 req.session.passport.user 에 user 정보가 저장되어 client 로 전달 된다. 가로 user에 관한 정보를 추가하고자 할 경우 passport.serializeUser() 함수 내에서 user['somefileld'] = somevalue 식으로 추가 하면 된다. 


// 성공시 정보를 session에 저장
passport.serializeUser((user,done) => {
    console.log("passport.serializeUser");
    done(null, user);
});
// session에  저장된 user 정보를 page접근시 마다 client로 전송
passport.deserializeUser((user,done) => {
    console.log("passport.deserializeUser");
    done(null, user);
});
...
app.post('/login', passport.authenticate('ldapauth'), (req, res) => {
        console.log(req);
        return res.send('로그인 성공');
    });


Session을 유지하기 위해서 express-session 모듈을 사용한다.

// sesson
app.use(session({
    secret : '!@#$IDISRNDASSETS!#$%',
    resave : false,
    saveUninitialized : true,
    cookie : { httpOnly : true, maxAge : 86400000} // maxAge in miliseconds.
})); // should be before passport.session


현재 session의 user 정보를 axios 등을 이용하여 ajax call 로 얻고자할 경우에는 아래와 같이 처리한다.

app.get('/user', (req, res) => {

    if (req.session.passport) {

        console.log("/user " + JSON.stringify(req.session.passport.user));

        return res.json(req.session.passport.user);

    }

    else {

        console.log("/user undefined");

        return res.json({'uid' : 'undefined'});

    }

});


/logout url에 대한 get 처리시 req.session.destory() 함수를 호출해서 session을 파괴한다.

app.get('/logout', (req, res) => {

    console.log("logout");

    req.session.destroy((err)=>{

        if (err) {

            return next(err);

        }

        req.user = null;

        res.redirect('/');

    });

});



전체 server side 프로그램은 아래와 같다.

import session from 'express-session';

import passport from 'passport';

import Ldap from 'passport-ldapauth';

...
var OPTS = {
    server : {
        url : 'ldap://gw.idis.co.kr:389',
        searchBase : 'O=IDIS',
        searchFilter : '(uid={{username}})',
    }
};
...
// 성공시 정보를 session에 저장
passport.serializeUser((user,done) => {
    console.log("passport.serializeUser");
    if (AdminGroup.includes(user.uid)) {  // session.passport.user 에 필드 추가
        user['gid'] = 'admin';
    }
    done(null, user);
});
// session에  저장된 user 정보를 page접근시 마다 client로 전송
passport.deserializeUser((user,done) => {
    console.log("passport.deserializeUser");
    done(null, user);
});
passport.use(new Ldap(OPTS));
...
// sesson
app.use(session({
    secret : '!@#$IDISRNDASSETS!#$%',
    resave : false,
    saveUninitialized : true,
    cookie : { httpOnly : true, maxAge : 86400000} // maxAge in miliseconds.
})); // should be before passport.session
...
app.use(passport.initialize());
app.use(passport.session()); // express session() 보다 뒤에 호출되어야 함.
...
app.post('/login', passport.authenticate('ldapauth'), (req, res) => {
        console.log(req);
        return res.send('로그인 성공');
    });

app.get('/user', (req, res) => {
    if (req.session.passport) {
        console.log("/user " + JSON.stringify(req.session.passport.user));
        return res.json(req.session.passport.user);
    }
    else {
        console.log("/user undefined");
        return res.json({'uid' : 'undefined'});
    }
});

app.get('/logout', (req, res) => {
    console.log("logout");
    req.session.destroy((err)=>{
        if (err) {
            return next(err);
        }
        req.user = null;
        res.redirect('/test');
    });
});


Client Side 프로그래밍 

client 쪽에서는 간단하게 form을 이용하여 ID인 username과 암호인 password를 입력받아 submit 시 axios로 /login url 에 대한 post를 request하면 된다. 아래 client code는 react-semantic 을 사용한 program이다.


onFormSubmit(e) {

    e.preventDefault(); // stop form submit

    const data = new FormData(e.target);

    let jsonData = {};

    let confirmPassword = "";

    for (const [key, value] of data.entries()) {

        if (key != 'confirmPassword') {

            jsonData[key] = value;

        }

        else {

            confirmPassword = value;

        }

    }

    if (jsonData['password'] != confirmPassword) {

        // 암호확인이 암호화 다름 

        return;

    }

    axios('/login',jsonData).then((response)=>{ // req.body.username 에 ID, req.body.password에 암호 저장된다.

        if (response.status === 200) { 

            window.location = '/'; // redirect

        }

        else {

            return;

        }

    }) // then

    .catch((err)=>{

        // 암호가 틀렸습니다.

   return;

    });

  }


'개발 > React & React Native' 카테고리의 다른 글

<React Native> Expo 설정  (0) 2018.05.22
React Native 환경설정  (0) 2018.05.21