[SPRING] EnableWebSecurity를 사용할 때 AuthenticationPrincipal이 비어 있습니다.
SPRINGEnableWebSecurity를 사용할 때 AuthenticationPrincipal이 비어 있습니다.
Spring Security doc : 34.1 @EnableWebMvcSecurity에서, @EnableWebMvcSecurity는 @EnableWebSecurity로 바뀌었다.
그러나 @AuthenticationPrincipal에 의해 컨트롤러에서 UserDetails를 가져 오려고하면 빈 개체가 생깁니다. 사용자 이름은 ""입니다. 또한 @EnableWebMvcSecurity를 시도했지만 불행히도 UserDetails는 null입니다.
그러나 나는 다음과 같이 전통적인 방식으로 UserDetails를 얻을 수있다.
SecurityContextHolder.getContext().getAuthentication().getPrincipal();
제 질문은 @EnableWebSecurity를 사용할 때 내 맞춤 UserDetails (계정)를 얻는 올바른 방법은 무엇입니까?
다음은 관련 소스 코드입니다.
제어 장치:
@RequestMapping(method = RequestMethod.POST)
@Secured("ROLE_USER")
public String postRoom(@Valid @ModelAttribute Room room, BindingResult result, Model model, @AuthenticationPrincipal Account principal) {
if (result.hasErrors()) {
return "room_form";
}
Account account = accountRepository.findByUsername(principal.getUsername());
room.setAccountId(account.getId());
room.setLastModified(new Date());
roomRepository.save(room);
return "room_list";
}
보안 구성 :
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private SecurityProperties security;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll()
.and().formLogin().loginPage("/login").failureUrl("/login?error").permitAll()
.and().logout().permitAll()
.and().rememberMe()
.and().csrf().disable();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(this.dataSource).passwordEncoder(new BCryptPasswordEncoder(8));
}
}
그리고 Account.java :
@Entity
@Table(name = "users")
public class Account implements Serializable {
@Id
@GeneratedValue
private Long id;
private String username;
private String password;
private boolean enabled;
@Lob
private byte[] avatar;
// getter / setter ...
}
해결법
-
==============================
1.이 게시물에 대한 의견 중 하나에서 언급했듯이, 반환하는 Account 클래스는 authentication.getPrincipal ()에서 할당 할 수 있어야합니다. 즉, Account 클래스가 org보다 UserDetails 인터페이스를 구현해야 할 가능성이 높습니다. springframework.security.core.userdetails.User 클래스가 수행합니다. UserDetails 또는이 페이지에 대한 Java의 API 문서를 살펴보십시오.
이 게시물에 대한 의견 중 하나에서 언급했듯이, 반환하는 Account 클래스는 authentication.getPrincipal ()에서 할당 할 수 있어야합니다. 즉, Account 클래스가 org보다 UserDetails 인터페이스를 구현해야 할 가능성이 높습니다. springframework.security.core.userdetails.User 클래스가 수행합니다. UserDetails 또는이 페이지에 대한 Java의 API 문서를 살펴보십시오.
@AuthenticationPrincipal 이후의 유형을 User로 변경하면 null 문제가 사라질 수 있습니다.
데이터베이스 설정 방법에 따라 Account 클래스가 UserDetails를 구현하게되면 모델로 간주되기 때문에 Account에 너무 많은 로직이 도입 될 수 있습니다.
@EnableWebSecurity를 사용하기 때문에 일부 게시물에서 제안하는 것처럼 사용자 정의 HandlerMethodArgumentResolver를 구성 할 필요가 없습니다.
참고 스프링 부트 사용
jdbcAuthentication을 사용하려면 사전 정의 된 방식으로 데이터베이스를 설정해야합니다 (그리고 가장 많이 염두에 둔 스키마는 작성한 스키마와 같지 않습니다). 가장 좋은 방법은 사용자 정의 스키마를 만들고 사용자 인증 서비스를 구성하는 것입니다 (어렵지 않다). 개인적으로 configureGlobal ... 메소드에서 사용자 정의 사용자 인증 서비스를 구성했습니다. 짧막 한 농담.
auth.userDetailsService(userService).passwordEncoder...
내 사용자 정의 userService는 공용 UserDetails를 구현할 수있는 하나의 메소드 만 제공하는 UserDetailsService 인터페이스를 구현합니다. loadUserByUsername (String username) Spring Security는 메소드를 호출하여 사용자를 인증합니다. 그 loadUserByUsername 메소드 내에서 데이터베이스로부터 사용자 정보를 검색하고 새로운 org.springframework.security.core.userdetails.User 객체를 만들고 사용자 이름, 비밀번호 및 사용 권한을 User 객체에 채운 다음 반환했습니다. 나는 나의 방법 끝에 다음과 같은 것을 가지고있다.
return new User(user.getUsername(), user.getPassword(), permissions);
UserDetails 인터페이스를 구현 한 User를 반환했기 때문에 @AuthenticationPrincipal User 사용자가 나를 대신 사용할 수 있습니다.
사용 권한 변수는 GrantedAuthority 인터페이스 또는 해당 유형의 컬렉션을 구현하는 클래스 여야합니다. 이 인터페이스에는 public String getAuthority ()를 구현하는 단 하나의 메소드 만 있습니다. 기본적으로 원하는 문자열 (데이터베이스의 권한 / 역할 이름)을 반환 할 수 있습니다.
Spring Security가 권한 부여를 다루는 방법을 알고 있다고 가정합니다. Spring Security가보다 세분화 된 제어를위한 그룹 + 권한 대신에 역할 기반 권한 부여 만 사용한다는 것은 슬픈 일입니다. 그러나 데이터베이스에 그룹 테이블과 권한 테이블을 만들고 해당 클래스가 GrantedAuthority 인터페이스를 구현하면이 문제를 해결할 수 있습니다. 당신은 효과적으로 두 범주로 "역할"을 분리 할 것입니다.
@AuthenticationPrincipal을 통해 자신의 클래스를 사용하고 싶거나 사용자 이름과 암호 이상을 원한다면 아마 Account 클래스에서 래퍼 클래스를 만들면 (Account에서 로직을 빼내기 위해) 래퍼 클래스가 UserDetails를 구현하도록 할 것입니다.
마지막으로 저장소 계층 위에 서비스 계층을 추가하고 컨트롤러가 서비스 계층과 통신하도록하는 것이 좋습니다. 이 설정은 해커가 저장소 계층에 도달하기 전에 해커가 서비스 계층을 해킹해야하므로 보안 계층을 추가하고 CRUD에 대해서만 사용해야하므로 저장소 계층 외부로 논리를 가져옵니다.
-
==============================
2.나는 그것을 시도하지 않았지만 이것은 당신을 위해 일해야합니다 :
나는 그것을 시도하지 않았지만 이것은 당신을 위해 일해야합니다 :
@Configuration public class MvcConfig extends WebMvcConfigurerAdapter { @Bean public AuthenticationPrincipalArgumentResolver authenticationPrincipalArgumentResolver(){ return new AuthenticationPrincipalArgumentResolver(); } @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(authenticationPrincipalArgumentResolver()); } }
-
==============================
3.나에게 도움이되는 인수 결정자의 구성
나에게 도움이되는 인수 결정자의 구성
<mvc:annotation-driven> <mvc:argument-resolvers> <bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver"/> </mvc:argument-resolvers> </mvc:annotation-driven>
또한 34.2 @AuthenticationPrincipal 섹션을 볼 수 있습니다.
이것이 내가 인수 분석자를 수동으로 추가해야한다는 것을 어떻게 이해하는지. 또는
관련 질문
-
==============================
4.나는 같은 문제를 만났다. 내 자신의 HandlerMethodArgumentResolver 및 주석을 만들어야했습니다. 다음 코드는 테스트를 거쳤으며 작동합니다.
나는 같은 문제를 만났다. 내 자신의 HandlerMethodArgumentResolver 및 주석을 만들어야했습니다. 다음 코드는 테스트를 거쳤으며 작동합니다.
먼저 주석을 작성하십시오.
@Target({ ElementType.PARAMETER, ElementType.ANNOTATION_TYPE }) @Retention(RetentionPolicy.RUNTIME) public @interface CurrentUser{}
간단한 구성
@Configuration @EnableWebMvc @ComponentScan(basePackages = "x.x.x") public class ApplicationConfiguration extends WebMvcConfigurerAdapter{ @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(new HandlerMethodArgumentResolver() { public boolean supportsParameter(MethodParameter parameter) { return findMethodAnnotation(CurrentUser.class, parameter) != null; } public Object resolveArgument( MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); Object principal = authentication.getPrincipal(); if(principal != null && !parameter.getParameterType().isAssignableFrom(principal.getClass())) throw new ClassCastException(principal + " is not assignable to " + parameter.getParameterType()); return principal; } <T extends Annotation> T findMethodAnnotation(Class<T> annotationClass, MethodParameter parameter) { T annotation = parameter.getParameterAnnotation(annotationClass); if(annotation != null) { return annotation; } Annotation[] annotationsToSearch = parameter.getParameterAnnotations(); for(Annotation toSearch : annotationsToSearch) { annotation = AnnotationUtils.findAnnotation(toSearch.annotationType(), annotationClass); if(annotation != null) { return annotation; } } return null; } }); } }
그런 다음 컨트롤러에서 사용하십시오.
@RequestMapping("/userget") public User message(@CurrentUser User user){ return user; }
User는 UserDetails를 anyamore 확장 할 필요가 없습니다. 희망이 (의지) 도움이 (들)
from https://stackoverflow.com/questions/29657039/authenticationprincipal-is-empty-when-using-enablewebsecurity by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] 스프링 MVC 폼 유효성 검사 날짜 필드 (0) | 2019.04.22 |
---|---|
[SPRING] IE는 NTLM 인증을 사용하는 동안 무작위로 빈 POST 본문을 보냅니다 (각도를 봄으로 사용). (0) | 2019.04.22 |
[SPRING] 단계별 스프링 배치 흐름 / 분할 (0) | 2019.04.22 |
[SPRING] 유닛 테스트를위한 객체 MockHttpServletResponse 생성 오류 (0) | 2019.04.22 |
[SPRING] Spring jdbcTemplate과 PreparedStatementSetter를 사용하여 생성 된 컬럼 id 값을 반환하는 방법을 모르고있다. (0) | 2019.04.22 |