알쓸전컴(알아두면 쓸모있는 전자 컴퓨터)

spring mvc 와 vue-auth with jwt 사용법 본문

Web /Vue js tip

spring mvc 와 vue-auth with jwt 사용법

백곳 2018. 9. 20. 11:36

spring mvc 와 vue-auth with jwt 사용법


vue-auth


일단 기본 적인 설정은


해당 문서에 나와 있는 방법을 사용 하였습니다.

하지만 해당 문서 만보고 하면서 시행 착오가 많아 정리 합니다.

아래와 같이 코드에 셋업 했습니다.

저같은 경우에 개발 보드에서 프록시 모드를 사용하기 때문에
vue.config.js
module.exports = {
baseUrl: 'webfms/',
devServer: {
proxy: {
'/W_Server': {
target: 'http://127.0.0.1:8181/test/',
changeOrigin: true,
pathRewrite: {
'^/W_Server': ''
}
}
}
}
}

아래와 같이 설정 했습니다.
main.js
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
Vue.axios.defaults.baseURL = '/W_Server/webfms/'
Vue.router = router
Vue.use(require('@websanova/vue-auth'), {
refreshData: {
interval: 30
},
auth: require('@websanova/vue-auth/drivers/auth/bearer.js'),
http: require('@websanova/vue-auth/drivers/http/axios.1.x.js'),
router: require('@websanova/vue-auth/drivers/router/vue-router.2.x.js')
})

// 해당 부분은 해당 프로젝트 이슈 부분에서 찾아낸 코드 입니다.

axios.interceptors.response.use(
response => {
return response
},
error => {
let index = error.response.data.indexOf('InvalidToken')
if ((error.response.status === 401) && (index > -1)) {
console.log('error')
Vue.auth.options.logoutProcess.call(Vue.auth, {}, {})
}
return Promise.reject(error)
})


여기서 옵션 사항중 많은 부분이 기본 Defalut 설정 되어 있어서

로그인 기능을 하기전에 아래 옵션 사이트를 보시기를 권장 합니다.


Login.vue

// 일부러 로그인 하는 부분의 메소드만 적었습니다.

methods:{
Login(e){
var redirect = this.$auth.redirect();
this.$auth.login({
data: {userid: "123123", password: "345534"},
redirect: {name: redirect ? redirect.from.name : 'home'},
});
}

'

위에 리디렉션 부분이 로그인이 필요한 페이지에 접근시에 밑에 두부분이

var redirect = this.$auth.redirect();

redirect: {name: redirect ? redirect.from.name : 'home'},


로그인 필요 페이지->로그인 페이지 자동으로 이동 ->로그인 완료후->로그인이 필요했던 페이지로 자동 라우팅 됩니다.


axios 을 사용하는 경우

보내는 데이터는 data 객체에 보내 줍니다.


위와 같이 로그인을 하게 되면


Vue.axios.defaults.baseURL 로 지정된 url 에서 /auth/login 붙힌 주소에 POST로토큰을 요청 하게 됩니다.




/auth/login 인 기본 설정으로 바꾸고 싶으면 위에 옵션 문서를 보고 바꿔 주시면 됩니다.


코드에는 안보이지만




위와 같이 바로 /auth/user 을 요청 하는데 


그이유는 

fetchUser: true,

부분이 자동 Defalut 설정이 되어 있기 때문입니다.


해당 부분을 false 하면 user을 자동으로 요청하지 않습니다.


하지만 경험상 거의 대부분 필요합니다.


아래 와 같이 유저 정보를 넣어줍니다.

Manually Setting User

Sometimes you may need to set your own user manually via some other method, perhaps from some token.

Vue.use(VueAuth, {

    ...

    loginData: {
        fetchUser: false
    },

    fetchData: {
        enabled: false,
        success: function () {
            var token = Vue.auth.token();
            
            Vue.auth.user(/* user object */);
        }
    },

    ...
});



유저 정보 사용은 아래와 같습니다.

<div>
    {{ $auth.user().email }}
</div>


이렇게 서버와 토큰 인증 과정이 진행 되는데 서버쪽 로직은 이에 맞춰서 코딩해줘야 합니다.


서버쪽은 아래에서 보겠습니다.



그리고 refresh 을 설정 했기 때문에 30분에 한번씩 /auth/refresh/ 의 주소로 새 토큰을 요청하게 됩니다.


새 토큰은 토큰 시간이 만료 되기 전에 받아 주시면 됩니다.



만약 refresh을 사용 하지 않으려면


refreshData: {
    enable:false, interval: 0
},
으로 옵션을 주면 됩니다.

만약 refresh 을 설정하지 않으면 App의 token 인증이 필요 하다는곳에 refresh 진행을 해줍니다.

그리고 route 설정 개념이 필요 합니다.


export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [

{
path: '/Login/',
//meta 부분이 중요 합니다.
//auth 가 false 가 되어 있으면 로그인 사용자는 들어가지못하는 페이지가 됩니다.
//로그인 부분에 false 로 해준 이유는 로그인 한사람이 login 페이지로 못들어가게 하는 의도 입니다.
//로그 아웃을 한다음에 들어 올수 있게 하는 설정입니다.
meta: {
auth: false
},
name: '로그인',
component: Login
},
{
path: '/account',
//해당 auth가 ture 로 되어 있으면 로그인이 안되어 있을때 로그인 페이지로 이동 하게 됩니다.
//기본 설정으로 루트 페이지의 /login 이 기본 로그인 페이지 로 설정 되어있으며
//해당 옵션을 변경하려면 authRedirect: {path: '/login'} 을 변경 해야 됩니다.
meta: {
auth: true
},
name: 'account',
component: Home
},

]
})


로그인 버튼 부분

<v-btn v-if="!$auth.check()" class="headline" to="/login">로그인</v-btn>
<v-btn v-if="$auth.check()" class="headline" @click="logout">로그아웃</v-btn>

위와 같이 $auth.check() 등을 통해서 현재 로그인 상태로 페이지를 보여 줄수 있습니다.

은 다음과 같이 간단히 했습니다.


logout(){
this.$auth.logout();
}


이로써 간단히? 사용법 을 알아 보았습니다.



Spring MVC


여기서는


1. auth/login

2 auth/refresh

3 auth/user 부분을 코딩해줘야 합니다.


W_controller_webfms.java

@Controller
public class W_controller_webfms {
    
    @Autowired
    webfmsDAOImpl webfms_DAO;

    @RequestMapping(value = "/webfms/auth/login", method = RequestMethod.POST)
    public void webfms_auth_login(HttpServletRequest request, HttpServletResponse response) {
        try {
            webfms_DAO.webfms_auth_login(request, response);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    @RequestMapping(value = "/webfms/auth/refresh", method = RequestMethod.GET)
    public void webfms_auth_refresh(HttpServletRequest request, HttpServletResponse response) {
        try {
            webfms_DAO.webfms_auth_refresh(request, response);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    @RequestMapping(value = "/webfms/auth/user", method = RequestMethod.GET)
    public void webfms_auth_user(HttpServletRequest request, HttpServletResponse response) {
        try {
            webfms_DAO.webfms_auth_user(request, response);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

위와 같이 기본적인 인증에서 사용되는 부분을 만들었습니다.


webfmsDAO.java


public interface webfmsDAO {
    public void webfms_auth_login(HttpServletRequest request, HttpServletResponse response) throws Exception;
    public void webfms_auth_user(HttpServletRequest request, HttpServletResponse response) throws Exception;
    public void webfms_auth_refresh(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
webfmsDAOImpl.java
@Repository
public class webfmsDAOImpl implements webfmsDAO {
    //2hour
    static final long EXPIRATIONTIME = 7200000;
    static final String SECRET = "fabwisol";
    static final String TOKEN_PREFIX = "Bearer";
    static final String HEADER_STRING = "Authorization";
   


    @Override
    public void webfms_auth_login(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // TODO Auto-generated method stub
        response.setContentType("text/plain");
        response.setCharacterEncoding("UTF-8");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.addHeader("Access-Control-Allow-Headers", "Authorization");
        response.addHeader("Access-Control-Expose-Headers", "Authorization");
        String body = IOUtils.toString(request.getReader());
        ObjectMapper recv_objectMapper = new ObjectMapper();
        Map<String, String> recv_map = recv_objectMapper.readValue(body, new TypeReference<Map<Object, Object>>(){});
        String userid = recv_map.get("userid");
        String username = "username";
        String jwt = Jwts.builder()
                .setSubject(userid)
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
                .claim("name",username)
                .claim("scope", "self groups/admins")
                .signWith(SignatureAlgorithm.HS256, SECRET.getBytes("UTF-8"))
                .compact();
        response.addHeader(HEADER_STRING, TOKEN_PREFIX + " "+jwt);
     
    }

    @Override
    public void webfms_auth_user(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // TODO Auto-generated method stub


  try {

//코드를 체크 해주는 부분 입니다.
            Jws<Claims> claims = Jwts.parser()
                     .setSigningKey(SECRET.getBytes("UTF-8"))
                     .parseClaimsJws(jwtstr);
            String userid = (String) claims.getBody().getSubject();
            String scope = (String) claims.getBody().get("scope");

//저는 따로 유저 정보를 테스트 코드라서 입력 안했지만 밑에 유저 정보를 입력 하여 해더를 주면 됩니다.

  String jwt = Jwts.builder()
                    .setSubject("userid")
                    .setExpiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
                    .claim("name","username")
                    .claim("scope", scope)
                    .signWith(SignatureAlgorithm.HS256, SECRET.getBytes("UTF-8"))
                    .compact();
            response.addHeader(HEADER_STRING, TOKEN_PREFIX + " "+jwt);


}catch (Exception e) {

            
       response.sendError(401,"InvalidToken");
       throw new Exception(e);
  }

    }

@Override
    public void webfms_auth_refresh(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // TODO Auto-generated method stub

        response.setContentType("text/plain");
        response.setCharacterEncoding("UTF-8");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.addHeader("Access-Control-Allow-Headers", "Authorization");
        response.addHeader("Access-Control-Expose-Headers", "Authorization");
        String jwtstr = request.getHeader("Authorization");
        jwtstr = jwtstr.replace("Bearer ", "");
        try {
//코드를 체크 해주는 부분 입니다.
            Jws<Claims> claims = Jwts.parser()
                     .setSigningKey(SECRET.getBytes("UTF-8"))
                     .parseClaimsJws(jwtstr);
            String userid = (String) claims.getBody().getSubject();
            String scope = (String) claims.getBody().get("scope");
           //토큰을 재성성 하여 보내 주도록 합니다.
            String jwt = Jwts.builder()
                    .setSubject(userid)
                    .setExpiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
                    .claim("name","username")
                    .claim("scope", scope)
                    .signWith(SignatureAlgorithm.HS256, SECRET.getBytes("UTF-8"))
                    .compact();
            response.addHeader(HEADER_STRING, TOKEN_PREFIX + " "+jwt);

        }catch (Exception e) {
            
            response.sendError(401,"InvalidToken");
            throw new Exception(e);
        }

}



이렇게 하면 기본적인 인증 과정은 걸치게 됩니다 이후는 App에 맞게 코딩해 사용 하면 될것 같습니다.

Comments