Spring Security, 로그인 처리 완료

main
semin.baek 6 months ago
parent 2fc4fa18cf
commit b1bea58188

@ -1,24 +1,22 @@
<script setup> <script setup>
import { RouterLink, RouterView } from 'vue-router' import { RouterLink, RouterView, useRouter } from 'vue-router'
import HelloWorld from './components/HelloWorld.vue' import { onMounted } from 'vue'
import Login from './views/LoginView.vue' import { userApi } from '@/components/userInfo'
const router = useRouter()
onMounted(() => {
userApi.loginCheck().then(() => {
if (userInfo.isLogin) {
router.push('/main.html')
} else {
router.replace('/login.html')
}
})
})
</script> </script>
<template> <template>
<!--
<header>
<img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />
<div class="wrapper">
<nav>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/about">About</RouterLink>
<RouterLink to="/login">Login</RouterLink>
<RouterLink to="/main">Main</RouterLink>
</nav>
</div>
</header>
-->
<RouterView class="flex-fill" /> <RouterView class="flex-fill" />
<footer class="w-100 border-top d-flex"> <footer class="w-100 border-top d-flex">
<div class="bg-info-subtle p-2 d-flex align-items-center w-100 bg-purple">바닥글(저작권, 링크 ) 영역</div> <div class="bg-info-subtle p-2 d-flex align-items-center w-100 bg-purple">바닥글(저작권, 링크 ) 영역</div>

@ -9,7 +9,7 @@ const userInfo = reactive({
export const userApi = { export const userApi = {
loginProcess: async function (inputUsername, inputUserPassword) { loginProcess: async function (inputUsername, inputUserPassword) {
const data = { username: inputUsername, password: inputUserPassword } const data = { username: inputUsername, password: inputUserPassword }
axios.post('/public-api/loginProcess', data).then((response) => { const response = await axios.post('/public-api/loginProcess', data, { withCredentials: true })
if (response.status == 200 && response.data && response.data.success == true) { if (response.status == 200 && response.data && response.data.success == true) {
userInfo.isLogin = true userInfo.isLogin = true
userInfo.userId = response.data.username userInfo.userId = response.data.username
@ -17,10 +17,9 @@ export const userApi = {
} else { } else {
return false return false
} }
})
}, },
logoutProcess: async function () { logoutProcess: async function () {
axios.post('/public-api/logoutProcess').then((response) => { const response = await axios.post('/public-api/logoutProcess')
if (response.status == 200 && response.data && response.data.success == true) { if (response.status == 200 && response.data && response.data.success == true) {
userInfo.isLogin = false userInfo.isLogin = false
userInfo.userId = '' userInfo.userId = ''
@ -28,10 +27,9 @@ export const userApi = {
} else { } else {
return false return false
} }
})
}, },
loginCheck: async function () { loginCheck: async function () {
axios.get('/public-api/sessionCheck').then((response) => { const response = await axios.get('/public-api/sessionCheck', { withCredentials: true })
if (response.status == 200 && response.data && response.data.success == true) { if (response.status == 200 && response.data && response.data.success == true) {
userInfo.isLogin = true userInfo.isLogin = true
userInfo.userId = response.data.username userInfo.userId = response.data.username
@ -41,8 +39,12 @@ export const userApi = {
userInfo.userId = '' userInfo.userId = ''
return false return false
} }
}) },
getEncryptText: async function (plainText) {
const response = await axios.post('/public-api/passwordGenerator', { password: plainText })
return response.data.password
}, },
} }
window.userApi = userApi window.userApi = userApi
window.userInfo = userInfo
export default userInfo export default userInfo

@ -1,5 +1,6 @@
<script setup> <script setup>
import { reactive } from 'vue' import { onMounted, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { userApi } from '@/components/userInfo' import { userApi } from '@/components/userInfo'
const loginForm = reactive({ const loginForm = reactive({
@ -7,6 +8,8 @@ const loginForm = reactive({
password: '', password: '',
}) })
const router = useRouter()
async function loginProcess() { async function loginProcess() {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
if (!emailRegex.test(loginForm.username)) { if (!emailRegex.test(loginForm.username)) {
@ -22,8 +25,15 @@ async function loginProcess() {
alert('사용자 아이디 또는 비밀번호가 일치하지 않습니다.') alert('사용자 아이디 또는 비밀번호가 일치하지 않습니다.')
document.getElementById('floatingPassword').focus() document.getElementById('floatingPassword').focus()
return return
} else {
router.push('/main.html')
} }
} }
async function loginCheck() {
let isLogin = await userApi.loginCheck()
alert(isLogin)
}
</script> </script>
<template> <template>
@ -32,18 +42,19 @@ async function loginProcess() {
<h1 class="h3 mb-3 fw-normal">Please sign in</h1> <h1 class="h3 mb-3 fw-normal">Please sign in</h1>
<div class="form-floating"> <div class="form-floating">
<input type="email" class="form-control" id="floatingInput" placeholder="name@example.com" :value="loginForm.username" /> <input type="email" class="form-control" id="floatingInput" placeholder="name@example.com" v-model="loginForm.username" />
<label for="floatingInput">Email address</label> <label for="floatingInput">Email address</label>
</div> </div>
<div class="form-floating"> <div class="form-floating">
<input type="password" class="form-control" id="floatingPassword" placeholder="Password" :value="loginForm.password" @keydown.enter="loginProcess" /> <input type="password" class="form-control" id="floatingPassword" placeholder="Password" v-model="loginForm.password" @keydown.enter="loginProcess" />
<label for="floatingPassword">Password</label> <label for="floatingPassword">Password</label>
</div> </div>
<div class="checkbox mb-3"> <div class="checkbox mb-3">
<label> <input type="checkbox" value="remember-me" /> Remember me </label> <label> <input type="checkbox" value="remember-me" /> Remember me </label>
</div> </div>
<button class="w-100 btn btn-lg btn-primary" type="submit" @submit="loginProcess">Sign in</button> <button class="w-100 btn btn-lg btn-primary" type="submit">Sign in</button>
<button class="w-100 btn btn-lg btn-primary" type="button" @click="loginCheck">login check</button>
<p class="mt-5 mb-3 text-muted">&copy; 20172021</p> <p class="mt-5 mb-3 text-muted">&copy; 20172021</p>
</form> </form>
</main> </main>

@ -7,11 +7,7 @@ import mkcert from 'vite-plugin-mkcert'
// https://vite.dev/config/ // https://vite.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [ plugins: [vue(), vueDevTools(), mkcert({ certFileName: 'bsm-lab.dev.pem', keyFileName: 'bsm-lab.dev-key.pem' })],
vue(),
vueDevTools(),
mkcert({ certFileName: 'bsm-lab.dev.pem', keyFileName: 'bsm-lab.dev-key.pem' }),
],
server: { server: {
port: 443, port: 443,
host: 'bsm-lab.dev', host: 'bsm-lab.dev',
@ -23,6 +19,13 @@ export default defineConfig({
secure: false, secure: false,
ws: true, ws: true,
}, },
'/public-api/': {
target: 'https://bsm-lab.dev:9443/public-api/',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/public-api/, ''),
secure: false,
ws: true,
},
}, },
}, },
base: '/', base: '/',

@ -2,8 +2,10 @@ package com.bsmlab.dfx.dfxconsole.framework.config;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain; import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
@ -11,7 +13,10 @@ import org.springframework.security.authentication.AuthenticationServiceExceptio
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
@ -40,14 +45,20 @@ public class JsonUsernamePasswordAuthenticationFilter extends UsernamePasswordAu
// 로그인 성공 후 결과 메시지 전달. 자동 호출됨. // 로그인 성공 후 결과 메시지 전달. 자동 호출됨.
@Override @Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException { protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
log.info("로그인 성공: {}", authResult.getName()); log.info("로그인 성공: {}", authResult.getName());
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
securityContext.setAuthentication(authResult);
SecurityContextHolder.setContext(securityContext);
HttpSession httpSession = request.getSession(true);
httpSession.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, securityContext);
response.setStatus(HttpServletResponse.SC_OK); response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("application/json"); response.setContentType("application/json");
Map<String, Object> result = new HashMap<>(); Map<String, Object> result = new HashMap<>();
result.put("success", true); result.put("success", true);
result.put("username", authResult.getName()); result.put("username", authResult.getName());
objectMapper.writeValue(response.getWriter(), result); objectMapper.writeValue(response.getWriter(), result);
chain.doFilter(request, response);
} }
// 로그인 실패 후 결과 메시지 전달. 자동 호출됨. // 로그인 실패 후 결과 메시지 전달. 자동 호출됨.

@ -9,6 +9,7 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import java.util.HashMap; import java.util.HashMap;
@ -26,7 +27,7 @@ public class PublicApiController {
* @return {"password": "암호화 문자열"} * @return {"password": "암호화 문자열"}
*/ */
@RequestMapping(value = "/public-api/passwordGenerator") @RequestMapping(value = "/public-api/passwordGenerator")
public ResponseEntity<?> passwordGenerator(Map<String, String> paramMap) { public ResponseEntity<?> passwordGenerator(@RequestBody Map<String, String> paramMap) {
Map<String, String> resultMap = new HashMap<>(); Map<String, String> resultMap = new HashMap<>();
String plainPassword = paramMap.get("password"); String plainPassword = paramMap.get("password");
if(StringUtils.isNotEmpty(plainPassword)) { if(StringUtils.isNotEmpty(plainPassword)) {

@ -37,7 +37,7 @@ server:
include-exception: true include-exception: true
include-message: always include-message: always
include-stacktrace: always include-stacktrace: always
port: 443 port: 9443
ssl: ssl:
enabled: true enabled: true
certificate: ${user.home}/.vite-plugin-mkcert/bsm-lab.dev.pem certificate: ${user.home}/.vite-plugin-mkcert/bsm-lab.dev.pem

Loading…
Cancel
Save