[英]How to retrieve principal information from HttpSessionEvent in Spring Boot?
[英]How to correctly retrieve the logged user information from a Spring MVC\Boot Controller method?
我是Spring Security 的新手,我有以下問題。
我正在使用Spring Security開發一個Spring Boot項目,以保護所有資源進入/Extranet/ ”。
所以基本上我的WebSecurityConfig配置類包含以下代碼:
@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = CustomUserDetailsService.class)
@EnableAutoConfiguration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/Extranet/**").access("hasRole('ROLE_USER')")
.anyRequest().permitAll()
.and()
.httpBasic()
.and()
.csrf().disable();
}
}
它工作正常,事實上以/Extranet/login訪問資源我必須設置基本身份驗證並指定正確的用戶名和密碼(使用Postman工具執行請求以測試它)。
好的,這很好用。
在我的 Spring Security 配置中,這個CustomUserDetails類實現了 Spring Security 接口UserDetails 。
public class CustomUserDetails extends User implements UserDetails {
private static final long serialVersionUID = 1L;
public CustomUserDetails(User user){
super(user);
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
for(UserRole role : this.getUserRoles() ){
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getName());
authorities.add(grantedAuthority);
}
return authorities;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public String getUsername() {
return super.getUsername();
}
}
此對象的實例包含當前登錄用戶的用戶詳細信息。
好的,我的疑問是:如何從控制器方法中檢索此對象? (我認為這應該在上下文中,我可以以某種方式檢索它)。
我嘗試這樣做:
@RestController
@RequestMapping("/Extranet")
public class AccessController {
@RequestMapping(value = "/login", method = RequestMethod.POST)
public ResponseEntity<String> login(CustomUserDetails userInfo) {
System.out.println("login() START");
return ResponseEntity.ok("LOGGED IN");
}
}
但通過這種方式,我獲得了這樣的異常:
[ERROR] 2017-01-23 14:18:04 [com.betrivius.controller.exceptionHandler.ControllerExceptionHandler.handleException(ControllerExceptionHandler.java:106)] [http-nio-8080-exec-1] ControllerExceptionHandler - Request: http://localhost:8080/Extranet/login throws:
org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.betrivius.security.bean.CustomUserDetails]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.betrivius.security.bean.CustomUserDetails.<init>()
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:105) ~[spring-beans-4.3.3.RELEASE.jar:4.3.3.RELEASE]
它似乎無法實例化CustomUserDetails對象。 為什么?
據我所知,我可以檢索與登錄用戶相關的CustomUserDetails對象。 我該怎么做?
我也嘗試這樣做:
@RequestMapping(value = "/login", method = RequestMethod.POST)
public ResponseEntity<String> login(Principal principal) {
System.out.println("login() START");
return ResponseEntity.ok("LOGGED IN");
}
通過這種方式, principal參數被正確實例化,並包含一個包含登錄用戶信息的先前CustomUserDetails對象的實例。
那么這是訪問當前登錄用戶信息的正確方法嗎?
另一個疑問是:為什么我可以將這個Principal 主體參數傳遞給我的login()方法? 引擎蓋下到底發生了什么? 誰將它有效地傳遞給login()方法?
我認為應該發生這樣的事情:
1) 有一個針對“/Extranet/login”資源的 POST HttpRequest。 調度程序 servlet 將其發送到login()方法。
2) 在為該資源啟用用戶之后(在調用控制器方法之前)將Principal 主體放入 Spring Context 中,因此 Spring 工廠可以從上下文中檢索它並將其傳遞給login()方法。
但我絕對不確定。 具體如何運作? 我錯過了什么?
您可能需要@AuthenticationPrincipal注釋:
@RequestMapping(value = "/login", method = RequestMethod.POST)
public ResponseEntity<String> login(@AuthenticationPrincipal CustomUserDetails userInfo) {
System.out.println("login() START");
return ResponseEntity.ok("LOGGED IN");
}
如果仍然不能解決問題,請嘗試使用舊方法進行調試:
@RequestMapping(value = "/login", method = RequestMethod.POST)
public ResponseEntity<String> login() {
CustomUserDetails userInfo = (CustomerUserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
...
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.