활동적인 사용자의 UserDetails를 얻는 방법
내 컨트롤러에서 활성 (로그인 된) 사용자가 필요할 때 UserDetails
구현 을 위해 다음을 수행하고 있습니다 .
User activeUser = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
log.debug(activeUser.getSomeCustomField());
잘 작동하지만 스프링이 이런 경우 인생을 더 쉽게 만들 수 있다고 생각합니다. (가)이 할 수있는 방법이 있나요 UserDetails
컨트롤러 나 방법 중 하나에를 autowire는?
예를 들면 다음과 같습니다.
public ModelAndView someRequestHandler(Principal principal) { ... }
그러나 대신을 얻는 UsernamePasswordAuthenticationToken
, 내가 얻을 UserDetails
대신을?
우아한 솔루션을 찾고 있습니다. 어떤 아이디어?
서문 : Spring-Security 3.2 이후 @AuthenticationPrincipal
로이 답변의 끝에 멋진 주석 이 있습니다. 이것은 Spring-Security> = 3.2를 사용할 때 가장 좋은 방법입니다.
때를:
- 이전 버전의 Spring-Security를 사용하십시오.
- 프린시 펄에 저장된 일부 정보 (로그인 또는 ID와 같은)로 데이터베이스에서 사용자 정의 사용자 오브젝트를로드해야합니다.
- 방법을 배우고 싶어
HandlerMethodArgumentResolver
하거나WebArgumentResolver
우아한 방법으로이 문제를 해결하거나 뒤에 배경을 배울 수있는 단지 원하는 수@AuthenticationPrincipal
와AuthenticationPrincipalArgumentResolver
(그것이 기반으로하기 때문에HandlerMethodArgumentResolver
)
그런 다음 계속 읽으십시오. 그렇지 않으면 @AuthenticationPrincipal
Rob Winch (저자 @AuthenticationPrincipal
)와 Lukas Schmelzeisen (자신의 답변) 에게 감사의 말씀을 전 합니다.
(BTW : 제 답변은 조금 더 오래되었으므로 (2012 년 1 월) Spring Security 3.2에 주석 솔루션 기반을 가진 최초의 사람으로 등장한 것은 Lukas Schmelzeisen 이었습니다 @AuthenticationPrincipal
.)
그런 다음 컨트롤러에서 사용할 수 있습니다
public ModelAndView someRequestHandler(Principal principal) {
User activeUser = (User) ((Authentication) principal).getPrincipal();
...
}
한 번 필요하면 괜찮습니다. 그러나 인프라 세부 정보로 컨트롤러를 오염시키기 때문에 추악한 일이 여러 번 필요한 경우 일반적으로 프레임 워크에 의해 숨겨져 야합니다.
따라서 실제로 원하는 것은 다음과 같은 컨트롤러를 갖는 것입니다.
public ModelAndView someRequestHandler(@ActiveUser User activeUser) {
...
}
따라서을 구현하기 만하면 WebArgumentResolver
됩니다. 방법이 있습니다
Object resolveArgument(MethodParameter methodParameter,
NativeWebRequest webRequest)
throws Exception
웹 요청 (두 번째 매개 변수)을 가져 와서 User
메소드 인수 (첫 번째 매개 변수)에 대한 책임이 있다고 생각되면 if 를 반환해야합니다 .
Spring 3.1부터라는 새로운 개념이 HandlerMethodArgumentResolver
있습니다. Spring 3.1 이상을 사용한다면 그것을 사용해야한다. (이 답변의 다음 섹션에 설명되어 있습니다)
public class CurrentUserWebArgumentResolver implements WebArgumentResolver{
Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) {
if(methodParameter is for type User && methodParameter is annotated with @ActiveUser) {
Principal principal = webRequest.getUserPrincipal();
return (User) ((Authentication) principal).getPrincipal();
} else {
return WebArgumentResolver.UNRESOLVED;
}
}
}
사용자 정의 주석을 정의해야합니다. 모든 사용자 인스턴스가 항상 보안 컨텍스트에서 가져와야하지만 명령 오브젝트가 아닌 경우이를 무시할 수 있습니다.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActiveUser {}
구성에서는 다음을 추가하기 만하면됩니다.
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"
id="applicationConversionService">
<property name="customArgumentResolver">
<bean class="CurrentUserWebArgumentResolver"/>
</property>
</bean>
@See : Spring MVC @Controller 메소드 인자를 커스터마이징하는 법 배우기
Spring 3.1을 사용하는 경우 WebArgumentResolver보다 HandlerMethodArgumentResolver를 권장합니다. -Jay의 코멘트보기
HandlerMethodArgumentResolver
Spring 3.1 이상 과 동일
public class CurrentUserHandlerMethodArgumentResolver
implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return
methodParameter.getParameterAnnotation(ActiveUser.class) != null
&& methodParameter.getParameterType().equals(User.class);
}
@Override
public Object resolveArgument(MethodParameter methodParameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
if (this.supportsParameter(methodParameter)) {
Principal principal = webRequest.getUserPrincipal();
return (User) ((Authentication) principal).getPrincipal();
} else {
return WebArgumentResolver.UNRESOLVED;
}
}
}
구성에서 이것을 추가해야합니다
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="CurrentUserHandlerMethodArgumentResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
@Spring MVC 3.1 HandlerMethodArgumentResolver 인터페이스 활용
스프링 보안 3.2 솔루션
Spring Security 3.2 (Spring 3.2와 혼동하지 마십시오)에는 자체 솔루션이 내장되어 있습니다 : @AuthenticationPrincipal
( org.springframework.security.web.bind.annotation.AuthenticationPrincipal
). 이것은 Lukas Schmelzeisen의 답변 에 잘 설명되어 있습니다.
그냥 쓰고 있어요
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
To get this working you need to register the AuthenticationPrincipalArgumentResolver
(org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver
) : either by "activating" @EnableWebMvcSecurity
or by registering this bean within mvc:argument-resolvers
- the same way I described it with may Spring 3.1 solution above.
@See Spring Security 3.2 Reference, Chapter 11.2. @AuthenticationPrincipal
Spring-Security 4.0 Solution
It works like the Spring 3.2 solution, but in Spring 4.0 the @AuthenticationPrincipal
and AuthenticationPrincipalArgumentResolver
was "moved" to an other package:
org.springframework.security.core.annotation.AuthenticationPrincipal
org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver
(But the old classes in its old packges still exists, so do not mix them!)
It is just writing
import org.springframework.security.core.annotation.AuthenticationPrincipal;
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
To get this working you need to register the (org.springframework.security.web.method.annotation.
) AuthenticationPrincipalArgumentResolver
: either by "activating" @EnableWebMvcSecurity
or by registering this bean within mvc:argument-resolvers
- the same way I described it with may Spring 3.1 solution above.
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
@See Spring Security 5.0 Reference, Chapter 39.3 @AuthenticationPrincipal
While Ralphs Answer provides an elegant solution, with Spring Security 3.2 you no longer need to implement your own ArgumentResolver
.
If you have a UserDetails
implementation CustomUser
, you can just do this:
@RequestMapping("/messages/inbox")
public ModelAndView findMessagesForUser(@AuthenticationPrincipal CustomUser customUser) {
// .. find messages for this User and return them...
}
See Spring Security Documentation: @AuthenticationPrincipal
Spring Security is intended to work with other non-Spring frameworks, hence it is not tightly integrated with Spring MVC. Spring Security returns the Authentication
object from the HttpServletRequest.getUserPrincipal()
method by default so that's what you get as the principal. You can obtain your UserDetails
object directly from this by using
UserDetails ud = ((Authentication)principal).getPrincipal()
Note also that the object types may vary depending on the authentication mechanism used (you may not get a UsernamePasswordAuthenticationToken
, for example) and the Authentication
doesn't strictly have to contain a UserDetails
. It can be a string or any other type.
If you don't want to call SecurityContextHolder
directly, the most elegant approach (which I would follow) is to inject your own custom security context accessor interface which is customized to match your needs and user object types. Create an interface, with the relevant methods, for example:
interface MySecurityAccessor {
MyUserDetails getCurrentUser();
// Other methods
}
You can then implement this by accessing the SecurityContextHolder
in your standard implementation, thus decoupling your code from Spring Security entirely. Then inject this into the controllers which need access to security information or information on the current user.
The other main benefit is that it is easy to make simple implementations with fixed data for testing, without having to worry about populating thread-locals and so on.
Implement the HandlerInterceptor
interface, and then inject the UserDetails
into each request that has a Model, as follows:
@Component
public class UserInterceptor implements HandlerInterceptor {
....other methods not shown....
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
if(modelAndView != null){
modelAndView.addObject("user", (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal());
}
}
Starting with Spring Security version 3.2, the custom functionality that has been implemented by some of the older answers, exists out of the box in the form of the @AuthenticationPrincipal
annotation that is backed by AuthenticationPrincipalArgumentResolver
.
An simple example of it's use is:
@Controller
public class MyController {
@RequestMapping("/user/current/show")
public String show(@AuthenticationPrincipal CustomUser customUser) {
// do something with CustomUser
return "view";
}
}
CustomUser needs to be assignable from authentication.getPrincipal()
Here are the corresponding Javadocs of AuthenticationPrincipal and AuthenticationPrincipalArgumentResolver
@Controller
public abstract class AbstractController {
@ModelAttribute("loggedUser")
public User getLoggedUser() {
return (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}
And if you need authorized user in templates (e.g. JSP) use
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<sec:authentication property="principal.yourCustomField"/>
together with
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring-security.version}</version>
</dependency>
You can try this: By Using Authentication Object from Spring we can get User details from it in the controller method . Below is the example , by passing Authentication object in the controller method along with argument.Once user is authenticated the details are populated in the Authentication Object.
@GetMapping(value = "/mappingEndPoint") <ReturnType> methodName(Authentication auth) {
String userName = auth.getName();
return <ReturnType>;
}
참고URL : https://stackoverflow.com/questions/8764545/how-to-get-active-users-userdetails
'IT' 카테고리의 다른 글
명명 규칙 : "상태"대 "상태" (0) | 2020.06.01 |
---|---|
Moq를 사용하여 단위 테스트를위한 비동기 메소드 조롱 (0) | 2020.06.01 |
파이썬 CSV 문자열을 배열로 (0) | 2020.06.01 |
vs (0) | 2020.06.01 |
파이썬 목록을 다른 "하위 목록"으로 분할합니다. 예 : 더 작은 목록 (0) | 2020.06.01 |