【问题标题】:Spring Security - Implementing UserDetailsServiceSpring Security - 实现 UserDetailsS​​ervice
【发布时间】:2017-03-22 14:03:03
【问题描述】:

我知道,如果我将主体作为方法参数包含在内,Spring 会将主体传递给控制器​​的方法。

我正在尝试通过实现UserDetailsService 来扩展此功能:

我创建了一个名为 CustomUserDetails 的类,它扩展了 org.springframework.security.core.userdetails.User

我创建了一个名为CustomUserDetailsService 的服务,它实现了UserDetailsService

例外

HTTP 状态 500 - 请求处理失败;嵌套异常是 java.lang.ClassCastException: org.springframework.security.authentication.UsernamePasswordAuthenticationToken 无法转换为 com.demo.model.CustomUserDetails

我的控制器方法中的以下行引发了异常:

CustomUserDetails userDetails = (CustomUserDetails) principal;  

Controller.java

@RequestMapping(value = "/dashboard", method = RequestMethod.GET)
    public ModelAndView displayHomePage(ModelAndView modelAndView, Principal principal, HttpServletRequest request) {

        // Throws exception here 
        CustomUserDetails userDetails = (CustomUserDetails) principal;      

        System.out.println(userDetails.getFirstName());

        // Tried this and it also throws exception
        // User cannot be cast to CustomUserDetails
        //Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        //CustomUserDetails userDetails = (CustomUserDetails)auth.getPrincipal();

        // Render template located at
        // src/main/resources/templates/dashboard.html
        modelAndView.setViewName("dashboard");

        return modelAndView;
    }

SecurityConfiguration.java

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    private DataSource dataSource;

    @Value("${spring.queries.users-query}")
    private String usersQuery;

    @Value("${spring.queries.roles-query}")
    private String rolesQuery;

    @Autowired
    SecurityHandler successHandler;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication().usersByUsernameQuery(usersQuery).authoritiesByUsernameQuery(rolesQuery)
                .dataSource(dataSource).passwordEncoder(bCryptPasswordEncoder);
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests().antMatchers("/").permitAll().antMatchers("/register*").permitAll()
                .antMatchers("/reset").permitAll().antMatchers("/forgot").permitAll().antMatchers("/grid").permitAll()
                .antMatchers("/login").permitAll().antMatchers("/admin/**").hasAuthority("ADMIN").anyRequest()
                .authenticated().and().formLogin().loginPage("/login").failureUrl("/login?error")
                .defaultSuccessUrl("/dashboard").successHandler(successHandler).usernameParameter("email")
                .passwordParameter("password").and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .logoutSuccessUrl("/login?logout").and().exceptionHandling().accessDeniedPage("/access-denied");

    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/error**", "/resources/**", "/static/**", "/css/**", "/js/**", "/img/**");
    }

}

CustomUserDetails.java

public class CustomUserDetails extends org.springframework.security.core.userdetails.User {

    public CustomUserDetails(String username, String password,
         Collection<? extends GrantedAuthority> authorities) {            
        super(username, password, authorities);
    }

    private String firstName;
    private String lastName;


    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

}

CustomUserDetailsS​​ervice.java

@Service
public class CustomUserDetailsService implements UserDetailsService{

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException{         

        if(StringUtils.isEmpty(userName)) 
            throw new UsernameNotFoundException("User name is empty");

        //if you don't use authority based security, just add empty set
        Set<GrantedAuthority> authorities = new HashSet<>();
        CustomUserDetails userDetails = new CustomUserDetails(userName, "", authorities);            

        userDetails.setFirstName("Testing: " + new Date());


        return userDetails;
    }

}

【问题讨论】:

  • 您获得的PrincipalAuthentication 对象,而不是您的用户。您可以致电getPrincipal 获取实际用户。 (这也是类转换异常告诉你的)。
  • 你能贴出实际抛出异常的代码吗?
  • @rptmat57 确定我添加了控制器方法代码
  • @M.Deinum 试过了,但仍然得到一个 ClassCastException 试图将 User 转换为 CustomUserDetails ....发布了控制器代码
  • 不,您正在直接投射principal。你应该把它剪成Authentication,然后在上面做getPrincipal

标签: java spring spring-mvc


【解决方案1】:

WebSecurityConfigurerAdapter,您需要添加您的注册自定义详细服务:

auth.userDetailsService(customDetailService)

     @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication().usersByUsernameQuery(usersQuery).authoritiesByUsernameQuery(rolesQuery)
                .dataSource(dataSource).passwordEncoder(bCryptPasswordEncoder);
    }

【讨论】:

    【解决方案2】:

    将您的控制器更改为:

    控制器

    @RequestMapping(value = "/dashboard", method = RequestMethod.GET)
    public ModelAndView displayHomePage(ModelAndView modelAndView, Authentication authentication, HttpServletRequest request) {
    
        CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal;      
    

    注意它返回一个 Authentication 对象。

    【讨论】:

      猜你喜欢
      • 2017-10-27
      • 2018-10-25
      • 2013-05-12
      • 2012-12-25
      • 2012-06-11
      • 2020-01-03
      • 1970-01-01
      • 1970-01-01
      • 2016-03-09
      相关资源
      最近更新 更多