스프링

 

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 주소에서 다음 이미와 같은 정보를 볼 수 있을 것이다.

 

 

 

 

 

 

 

about author

PHRASE

Level 60  라이트

벗 따라 강남 간다 , [꼭 가야 할 일은 아니나] 벗이 좋아 먼 길도 싫어하지 않고 간다는 말.

댓글 ( 4)

댓글 남기기

작성