programing

스프링 보안에서 현재 로그인한 사용자 개체를 가져오는 방법은 무엇입니까?

batch 2023. 7. 25. 20:46
반응형

스프링 보안에서 현재 로그인한 사용자 개체를 가져오는 방법은 무엇입니까?

Spring 보안 버전 3.1.4를 사용하고 있습니다.풀어주다.현재 로그인한 사용자 개체에 액세스하려면 어떻게 해야 합니까?

SecurityContextHolder.getContext().getAuthentication().getPrincipal()

사용자 개체가 아닌 사용자 이름을 반환합니다.그러면 반환된 사용자 이름을 사용하고 UserDetails 개체를 가져오려면 어떻게 해야 합니까?

다음 코드를 사용해 보았습니다.

public UserDetails getLoggedInUser(){

    final Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    if (auth != null && auth.isAuthenticated() && !(auth instanceof AnonymousAuthenticationToken))
    {
        if(auth.getDetails() !=null)
            System.out.println(auth.getDetails().getClass());
        if( auth.getDetails() instanceof UserDetails)
        {
            System.out.println("UserDetails");
        }
        else
        {
            System.out.println("!UserDetails");
        }
    }
    return null;
}

결과는 다음과 같습니다.

[2015-08-17 19:44:46.738] INFO  http-bio-8443-exec-423   System.out    class org.springframework.security.web.authentication.WebAuthenticationDetails 
[2015-08-17 19:44:46.738] INFO  http-bio-8443-exec-423   System.out    !UserDetails

AuthenticationFilter 클래스는 다음과 같습니다.

public class CustomUsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "j_username";
    public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "j_password";
    public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME";
    private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
    private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
    private boolean postOnly = true;

    public CustomUsernamePasswordAuthenticationFilter() {
        super("/j_spring_security_check");
    }

    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }

        String username = obtainUsername(request);
        String password = obtainPassword(request);
        if (username == null) {
            username = "";
        }
        if (password == null) {
            password = "";
        }
        username = username.trim();
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);

        // Allow subclasses to set the "details" property
        setDetails(request, authRequest);
        if(this.getAuthenticationManager()==null){
            logger.info("Authentication manager is null.");
        } else {
            logger.info("Authentication manager was "+this.getAuthenticationManager().getClass().getName()); 
        }
        return this.getAuthenticationManager().authenticate(authRequest);
    }

    protected String obtainPassword(HttpServletRequest request) {
        return request.getParameter(passwordParameter);
    }

    protected String obtainUsername(HttpServletRequest request) {
        return request.getParameter(usernameParameter);
    }

    protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }

    public void setUsernameParameter(String usernameParameter) {
        this.usernameParameter = usernameParameter;
    }

    public void setPasswordParameter(String passwordParameter) {
        this.passwordParameter = passwordParameter;
    }

    public void setPostOnly(boolean postOnly) {
        this.postOnly = postOnly;
    }

    public final String getUsernameParameter() {
        return usernameParameter;
    }

    public final String getPasswordParameter() {
        return passwordParameter;
    }
}

인증 공급자는 다음과 같습니다.

@Component
public class CustomAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
    private MyUserDetailsService userDetailsService;

    public MyUserDetailsService getUserDetailsService() {
        return userDetailsService;
    }

    public void setUserDetailsService(MyUserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Override
    protected void additionalAuthenticationChecks(UserDetails arg0,
            UsernamePasswordAuthenticationToken arg1)
            throws AuthenticationException {

    }

    @Override
    protected UserDetails retrieveUser(String arg0,
            UsernamePasswordAuthenticationToken arg1)
            throws AuthenticationException {
        return userDetailsService.loadUserByUsername(arg0);
    }
}

UserDetails 클래스는 다음과 같습니다.

    public class MyUserDetailsService implements UserDetailsService {       
    private final Map<String, UserDetails> usersList;
    
    public MyUserDetailsService() {
        Collection<GrantedAuthority> authorityList;
        final SimpleGrantedAuthority supervisorAuthority = new SimpleGrantedAuthority("supervisor");
        final SimpleGrantedAuthority userAuthority = new SimpleGrantedAuthority("user");
        usersList = new TreeMap<String, UserDetails>();

        authorityList = new ArrayList<GrantedAuthority>();
        authorityList.add(supervisorAuthority);
        authorityList.add(userAuthority);
        usersList.put("admin", new User("admin", "admin", authorityList));

        authorityList = new ArrayList<GrantedAuthority>();
        authorityList.add(userAuthority);
        usersList.put("peter", new User("peter", "password123", authorityList));

        //probably don't use this in production
        for(Map.Entry<String, UserDetails> user : usersList.entrySet()){
            logger.info(user.getValue().toString());
        }
    }

    @Override
    public UserDetails loadUserByUsername(String username)throws UsernameNotFoundException {
        UserDetails ud = usersList.get(username);
        if (ud != null) {
            logger.info("loadUserByUsername: found match, returning "
                    + ud.getUsername() + ":" + ud.getPassword() + ":"
                    + ud.getAuthorities().toString());
            return new User(ud.getUsername(), ud.getPassword(),
                    ud.getAuthorities());
        }

        logger.info("loadUserByUsername: did not find match, throwing UsernameNotFoundException");
        throw new UsernameNotFoundException(username);
    }
}
SecurityContextHolder.getContext().getAuthentication().getPrincipal();

현재 사용자 개체를 반환합니다.이것은 가능합니다.User,UserDetails또는 사용자 지정 사용자 개체입니다.반환 개체를 다음으로 캐스팅해야 합니다.UserDetails또는 사용자 지정 개체인 경우 사용자 개체입니다.

또는 주사할 수 있습니다.Authentication또는Principal컨트롤러에 직접 연결됩니다.원칙은 당신의 것입니다.UserDetails/custom 사용자 개체입니다.

참고:UserDetails인터페이스입니다.

당신은 그것을 사용할 수 있습니다.

Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

if (principal instanceof UserDetails) {
String username = ((UserDetails)principal).getUsername();
} else {
String username = principal.toString();
}

그것은 봄 보안 참조 http://docs.spring.io/spring-security/site/docs/4.0.2.RELEASE/reference/htmlsingle/ # 현재 사용자에 대한 정보입니다.

아래와 같이 컨트롤러에 인증 인터페이스를 주입하고 로그인한 사용자의 사용자 이름을 가져올 수 있습니다.

    @GetMapping(value = "/username")
    @ResponseBody
    public String currentUserName(Authentication authentication) {
    
        if (authentication != null)
            return authentication.getName();
        else
            return "";
    }

당신은 방금 한 발짝 더 나갔습니다.SecurityContextHolder.getContext().getAuthentication()반환합니다.Authentication물건.어떻게 사용자를 인증했는지, 그리고 구체적인 클래스가 구현할 수 있는 것은 무엇인지 알아야 합니다.Authentication의 하위 클래스라고 가정합니다.AbstractAuthenticationToken(제공되는 모든 봄 구현은 다음과 같습니다.)getDetails()를 반환합니다.UserDetails다음을 사용할 수 있습니다.

AbstractAuthenticationToken auth = (AbstractAuthenticationToken)
    SecurityContextHolder.getContext().getAuthentication();
UserDetails details = (UserDetails) auth.getDetails();

저는 이 문제를 사용하여 해결했습니다.SecurityContextHolder그리고.Authentication.getName():

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
        
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

String login = authentication.getName();

User user = usersService.getUserByLogin(login);

버전 5.2부터는 CurrentSecurityContext 주석을 사용하여 현재 사용자 인증을 받을 수 있습니다.

@GetMapping("/authentication")
public Object authentication(@CurrentSecurityContext(expression="authentication")
                             Authentication authentication) {
    return authentication.getDetails();
}

또는 심지어:

@GetMapping("/hello")
public String hello(@CurrentSecurityContext(expression="authentication.name")
                    String username) {
    return "Hello, " + username + "!";
}

현재 사용자의 모든 속성을 가져오려면 먼저 다음을 구현하는 클래스로 이동합니다.UserDetails라고 불릴 가능성이 더 높습니다.UserPrincipal각 속성에 대해 다음과 같은 get method를 작성합니다.getAge()두번째로 HTML 파일로 가서 이것을 씁니다.

<span th:text="${#request.userPrincipal.principal.age}> </span>

그리고 컨트롤러에 ModelAttribute를 추가할 필요가 없습니다. 문제가 해결되기를 바라며, 저에게 물어볼 수 있습니다.

다음을 통해 현재 로그인 사용자를 얻을 수 있습니다.

  1. @Authenticationprincipal

  2. SecurityContextHolder.getContext().getAuthentication().getPrinciple()

구현된 클래스로 주체를 다운캐스트해야 합니다. 그런 다음 securityContext에서 설정한 컨텍스트 개체를 추출할 수 있습니다.

 AbstractAuthenticationToken a = (AbstractAuthenticationToken) request.getUserPrincipal();
 UserContext context = (UserContext) a.getPrincipal();

이 솔루션은 Spring Boot 2.5에서 작동했습니다.

먼저, 다음을 정의합니다.User Principal학급

public class UserPrincipal implements UserDetails {

    private static final long serialVersionUID = 1L;
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
    // other methods ....
}

둘째, 다음을 정의합니다.User 명령어:

public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;
    String username;
    String password;
    //getters ans setters ...
}

셋째, 다음을 정의합니다.UserAuth 명령어:

 public class UserAuth {
    
     public String getUsername()
     {
         UserPrincipal principal 
             = (UserPrincipal)SecurityContextHolder
                 .getContext()
                 .getAuthentication()
                 .getPrincipal();
         return principal.getUser().getUsername();
    }
}

마지막으로, 당신은 자동 배선할 수 있습니다.UserAuth필요에 따라 수업합니다.

public class User implements UserDetails {

    private String firstname;
    private String lastname;

}

사용자 정의 사용자가 UserDetails 클래스를 구현하고 있다고 가정합니다.

@RestController
@RequestMapping("/api/user")
class UsersController {

    @GetMapping
    public User fetchUser(@AuthenticationPrincipal User user) {
        return user;
    }
}

그래서 거의 모든 대답이 올바르고 실현 가능해 보입니다. 모든 기여자들에게 칭찬이지만 상용판 코드를 제거하는 것은 유용하고 쉬울 수 있습니다. 모든 유틸리티 방법을 포함하는 인터페이스와 그 구현을 만들고, 그 다음에는 간단하게 만들 수 있습니다.@Autowire 거그거.

public interface AuthHelper {
    Authentication getAuthentication();
    public String getName();
    public UserDetails getUserDetails()
}
@Component
public class AuthHelperImpl implements AuthHelper {

    @Override
    public Authentication getAuthentication() {
        return SecurityContextHolder.getContext().getAuthentication();
    }
    public String getName() {
        return getAuthentication().getName();
    }
    public UserDetails getUserDetails() {
        return (UserDetails) getAuthentication().getPrincipal();
    }
//and more utilities you need
//you can also cast with UserPrincipal
}

이제 컨트롤러에서:

@Controller
public class DemoController {
    @Autowired
    private AuthHelper authHelper;

    @RequestMapping(value = "/username", method = RequestMethod.GET)
    @ResponseBody
    public String currentUserNameSimple() {
        return authHelper.getName;
    }
}

이것은 읽기에 좋은 기사일 수 있습니다.이 문서에서는 스프링 응용 프로그램에서 사용자 정보를 가져오는 방법을 공통 정적 액세스 메커니즘에서 시작하여 주체를 주입하는 몇 가지 더 나은 방법을 보여 줍니다.

https://www.baeldung.com/get-user-in-spring-security

언급URL : https://stackoverflow.com/questions/32052076/how-to-get-the-current-logged-in-user-object-from-spring-security

반응형