我是 Spring Security 的新手,我遇到了以下问题。
我正在使用 Spring Security 处理 Spring Boot 项目,以保护所有资源为 / Extranet / &#34;。< / p>
基本上我的 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 principal 参数传递给我的 login()方法?引擎盖下究竟发生了什么?谁有效地将其传递给 login()方法?
我认为应该发生这样的事情:
1)对于&#34; / Extranet / login&#34;有一个POST HttpRequest。资源。调度程序servlet将其发送到 login()方法。
2) Principal principal 被放入Spring Context后,用户启用了此资源(之前调用了控制器方法),因此Spring工厂可以从上下文中检索它将其传递给 login()方法。
但我绝对不确定。究竟如何运作?我错过了什么?
答案 0 :(得分: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();
...
}