簡體   English   中英

如何從 Spring MVC\\Boot Controller 方法中正確檢索登錄的用戶信息?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM