繁体   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