Spring Security 에서 현재 인증된(로그인한) 사용자의 정보를 가져오는 방법 에 대해 살펴볼 것 입니다. 스프링의 다양한 메카니즘을 통해 현재 로그인 중인 사용자의 정보를 가져올 수 있는데, 대표적인 몇 가지를 살펴보겠습니다.
1. Bean 에서 사용자 정보 얻기
가장 간단한 방법은 전역에 선언된 SecurityContextHolder을 이용하여 가져오는 방법입니다.
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); UserDetails userDetails = (UserDetails)principal; String username = principal.getUsername(); String password = principal.getPassword();
2. Controller 에서 사용자 정보 얻기
@Controller로 선언된 bean 객체에서는 메서드 인자로 Principal 객체에 직접 접근할 수 있는 추가적인 옵션이 있습니다.
@Controller public class SecurityController {
@GetMapping("/username")
@ResponseBody
public String currentUserName(Principal principal) {
return principal.getName();
}
}
principal 객체 뿐만 아니라 authentication 토큰 또한 사용할 수 있습니다.
@Controller public class SecurityController {
@GetMapping("/username")
@ResponseBody
public String currentUserName(Authentication authentication) {
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
return userDetails.getUsername();
}
}
3. @AuthenticationPrincipal
Spring Security 3.2 부터는 annotation을 이용하여 현재 로그인한 사용자 객체를 인자에 주입할 수 있습니다.
만약 UserDetails 를 구현한 CustomUser 클래스가 있고, UserDetailsService 구현체에서 CustomUser 객체를 반환한다고 가정합시다.
(가장 흔한 케이스)
@Data
public class CustomUser implements UserDetails {
// ...
}
@Service
public class UserSerivce implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws
UsernameNotFoundException {
CustomUser customUser = null; // ... DB 등을 통해 사용자 정보를 셋팅
return customUser;
}
다음과 같이 @AuthenticationPrincipal를 이용하여 CustomUser 객체를 인자에 넘겨줄 수 있습니다.
@Controller
public class SecurityController {
@GetMapping("/messages/inbox")
public ModelAndView currentUserName(@AuthenticationPrincipal CustomUser
customUser) {
String username = customUser.getUsername();
// .. find messages for this user and return them ...
}
}
출처: http://itstory.tk/entry/Spring-Security-현재-로그인한-사용자-정보-가져오기 [덕's IT Story]
* DB에서 정보 불러오기
테스트를 위해 다음과 같이 hobby 컬럼을 추가 했다.
alter table users add COLUMN hobby VARCHAR(30) ;

loginMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 다른 mapper와 중복되지 않도록 네임스페이스 기재 -->
<mapper namespace="net.macaronics.mapper.loginMapper">
<select id="getLoginUser" resultType="net.macaronics.web.domain.UserVO" >
select * from users WHERE username =#{username}
</select>
</mapper>
UserVO
1. UserDetails 를 상속받고 있다는 점이 중요하다.
2. UserDetails 를 상속받는 정보를 저장하기 위해 다음과 같은 필드를 만든후 setter 를 메소드를 생성한다.
/**
* <pre>
* 1. 패키지명 : net.macaronics.web.domain
* 2. 타입명 : UserVO.java
* 3. 작성일 : 2017. 11. 24. 오후 7:29:45
* 4. 저자 : 최준호
*
* </pre>
*
*/
package net.macaronics.web.domain;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
public class UserVO implements UserDetails {
private String username;
private String password;
private String hobby;
//UserDetails 를 상속받는 정보를 저장하기 위해 다음과 같은 필드를 만든후 setter 를 메소드를 생성한다.
private Collection<? extends GrantedAuthority> authorities;
private boolean isAccountNonExpired;
private boolean isAccountNonLocked;
private boolean isCredentialsNonExpired;
private boolean isEnabled;
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// TODO Auto-generated method stub
return authorities;
}
@Override
public String getPassword() {
// TODO Auto-generated method stub
return password;
}
@Override
public String getUsername() {
// TODO Auto-generated method stub
return username;
}
@Override
public boolean isAccountNonExpired() {
// TODO Auto-generated method stub
return isAccountNonExpired;
}
@Override
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return isAccountNonLocked;
}
@Override
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return isCredentialsNonExpired;
}
@Override
public boolean isEnabled() {
// TODO Auto-generated method stub
return isEnabled;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
this.authorities = authorities;
}
public void setAccountNonExpired(boolean isAccountNonExpired) {
this.isAccountNonExpired = isAccountNonExpired;
}
public void setAccountNonLocked(boolean isAccountNonLocked) {
this.isAccountNonLocked = isAccountNonLocked;
}
public void setCredentialsNonExpired(boolean isCredentialsNonExpired) {
this.isCredentialsNonExpired = isCredentialsNonExpired;
}
public void setEnabled(boolean isEnabled) {
this.isEnabled = isEnabled;
}
@Override
public String toString() {
return "UserVO [username=" + username + ", password=" + password + ", hobby=" + hobby + ", authorities="
+ authorities + ", isAccountNonExpired=" + isAccountNonExpired + ", isAccountNonLocked="
+ isAccountNonLocked + ", isCredentialsNonExpired=" + isCredentialsNonExpired + ", isEnabled="
+ isEnabled + "]";
}
}
UserDAO
/**
* <pre>
* 1. 패키지명 : net.macaronics.web.service
* 2. 타입명 : UserSerivce.java
* 3. 작성일 : 2017. 11. 24. 오후 7:28:15
* 4. 저자 : 최준호
*
* </pre>
*
*/
package net.macaronics.web.persistence;
import net.macaronics.web.domain.UserVO;
public interface UserDAO {
public UserVO getLoginUser(String username) throws Exception;
}
UserDAOImpl
/**
* <pre>
* 1. 패키지명 : net.macaronics.web.persistence
* 2. 타입명 : UserDAOImpl.java
* 3. 작성일 : 2017. 11. 25. 오후 1:53:53
* 4. 저자 : 최준호
*
* </pre>
*
*/
package net.macaronics.web.persistence;
import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import net.macaronics.web.domain.UserVO;
@Repository
public class UserDAOImpl implements UserDAO {
private static final Logger log = LoggerFactory.getLogger(UserDAOImpl.class);
//private static final String namespace="net.macaronics.mapper.o.memberMapper.";
private static final String namespace = "net.macaronics.mapper.loginMapper.";
@Autowired
private SqlSession sqlSession;
@Override
public UserVO getLoginUser(String username) throws Exception{
// TODO Auto-generated method stub
return sqlSession.selectOne(namespace+"getLoginUser", username);
}
}
UserSerivce
3. DB 등을 통해 사용자 정보를 셋팅
/**
* <pre>
* 1. 패키지명 : net.macaronics.web.service
* 2. 타입명 : UserSerivce.java
* 3. 작성일 : 2017. 11. 24. 오후 7:28:15
* 4. 저자 : 최준호
*
* </pre>
*
*/
package net.macaronics.web.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import net.macaronics.web.domain.UserVO;
import net.macaronics.web.persistence.UserDAO;
@Service
public class UserSerivce{
@Autowired
private UserDAO userDAO;
public UserVO loadUserByUsername(String username) throws Exception {
UserVO userVO = null;
// ... DB 등을 통해 사용자 정보를 셋팅
try {
userVO=userDAO.getLoginUser(username);
} catch (Exception e) {
e.printStackTrace();
}
return userVO;
}
}
SecurityController
Authentication 를 이용해서 시큐리티 UserDetails 클래스 정보를 가져온다.
이 정보의 아이디를 이용해서 로그인 한 유저정보를 불러올 수 있다.
DB 에서 불러온 유저 정보에 UserDetails 정보 저장 시킨다.
/**
* <pre>
* 1. 패키지명 : net.macaronics.web.controller
* 2. 타입명 : SecurityController.java
* 3. 작성일 : 2017. 11. 24. 오후 7:11:12
* 4. 저자 : 최준호
*
* </pre>
*
*/
package net.macaronics.web.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import net.macaronics.web.domain.UserVO;
import net.macaronics.web.service.UserSerivce;
@Controller
public class SecurityController {
private static Logger logger =LoggerFactory.getLogger(SecurityController.class);
@Autowired
private UserSerivce userService;
@GetMapping("/loginInfo")
public String currentUserName(Authentication authentication, Model model) throws Exception{
if(authentication !=null){
logger.info("userVO.getUsername() {} : " , authentication.getName());
//시큐리티에서 UserDetails 이용하여 로그인 정보를 불러온다.
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
// 아이디를 이용하여 DB 에서 정보를 불러 온다.
UserVO userVO=userService.loadUserByUsername(authentication.getName());
// DB 에서 불러온 정보를 userVO 객체에 저장한다.
//권한 저장 및 UserDetails 정보 저장
userVO.setAuthorities(userDetails.getAuthorities());
userVO.setAccountNonExpired(userDetails.isAccountNonExpired());
userVO.setAccountNonLocked(userDetails.isAccountNonLocked());
userVO.setCredentialsNonExpired(userDetails.isCredentialsNonExpired());
userVO.setEnabled(userDetails.isEnabled());
logger.info(" userDetails 출력 : {} " , userDetails.toString());
logger.info("출력 : {} " , userVO.toString());
model.addAttribute("userVO", userVO);
}
return "home";
}
}
home.jsp
<%@page import="net.macaronics.web.domain.UserVO"%>
<%@page import="org.springframework.security.core.userdetails.User"%>
<%@page import="org.springframework.security.core.context.SecurityContextHolder"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ page session="false"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="sec"
uri="http://www.springframework.org/security/tags"%>
<html>
<head>
<title>Home</title>
</head>
<body>
<h1>Home!</h1>
<sec:authorize access="isAnonymous()">
<p>
<a href="<c:url value="/login/loginForm.do" />">로그인</a>
</p>
</sec:authorize>
<sec:authorize access="isAuthenticated()">
<form:form action="${pageContext.request.contextPath}/logout"
method="POST">
<input type="submit" value="로그아웃" />
</form:form>
</sec:authorize>
<h3>
[<a href="<c:url value="/user/introduction.do" />">소개 페이지</a>] [<a
href="<c:url value="/admin/adminHome.do" />">관리자 홈</a>]
</h3>
<sec:authorize access="isAuthenticated()">
<%
User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if(user!=null){
System.out.println("username = " + user.toString());
out.write(user.getUsername());
}
%>
</sec:authorize>
<c:if test="${ not empty userVO }">
<br>
<h2>로그인한 정보 DB에서 개별 상세 정보 가져오기</h2>
${userVO.toString() }
</c:if>
</body>
</html>
다음과 같이 로그한 유저의 개인정보들을 출력시켜 줄 수 있다.
또한, 이러한 정보를 세션에 저장 시켜 유지 시켜 줘도 될 것이다.
다음은 콘솔에 찍힌 출력물이다.
INFO : net.macaronics.web.controller.SecurityController - userDetails 출력 : org.springframework.security.core.userdetails.User@6a68dc7: Username: user2; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER
INFO : net.macaronics.web.controller.SecurityController - 출력 : UserVO [username=user2, password=1, hobby=등산, authorities=[ROLE_USER], isAccountNonExpired=true, isAccountNonLocked=true, isCredentialsNonExpired=true, isEnabled=true]
username = org.springframework.security.core.userdetails.User@6a68dc7: Username: user2; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER
정상적으로 작동한다면 http://localhost:5050/loginInfo 주소에서 다음 이미와 같은 정보를 볼 수 있을 것이다.


















댓글 ( 4)
댓글 남기기