2017-01-23 67 views
1

我很新Spring Security我有以下问题。 。如何从Spring MVC Boot Controller方法正确检索记录的用户信息?

我正在使用春季安全,以保护所有的资源投入到/外网/”一春引导 prject

所以基本上我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我必须设置基本身份验证并指定正确的用户名和密码(使用邮递员工具来执行请求来测试它)。

好吧,这工作正常。

在我的春季安全配置involed这个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(); 
    } 

} 

此对象的实例包含当前登录的用户的用户详细信息。

好吧,我的疑问是:我如何从控制器方法检索这个对象? (我认为这应该是在上下文中,我可以以某种方式检索它)。

我已经tryied这样做:

@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] 

看来,它不能instantialete的CustomUserDetails目的。为什么?

从我所知我可以检索CustomUserDetails与记录的用户相关的对象。我该怎么做?

我也试着这样做:

@RequestMapping(value = "/login", method = RequestMethod.POST) 
public ResponseEntity<String> login(Principal principal) { 

    System.out.println("login() START"); 

    return ResponseEntity.ok("LOGGED IN"); 
} 

这样的本金参数是否正确实例化,包含以前CustomUserDetails包含登录用户的信息对象的实例。

那么,它是访问当前记录的用户信息的正确方法吗?

另一个疑问是:为什么我可以在此主要本金参数传递给我的登录()方法?究竟发生了什么?谁有效地将它传递给登录()方法?

我认为应该发生这样的事情:

1)有一个POST的HttpRequest朝着“/外网/登录”资源。调度程序servlet将其发送给登录()方法。

2)校长在用户启用此资源之前(在调用控制器方法之前)被放入Spring Context中,因此Spring工厂可以从上下文中检索它并将其传递给login()方法。

但我绝对不确定它。如何工作?我错过了什么?

回答

2

你可能需要再@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(); 
    ... 
}  
相关问题