我无法从Spring Security Context中检索当前的自定义用户对象

时间:2018-10-08 15:04:13

标签: java spring-security

我正在使用LDAP身份验证提供程序(活动目录)+ JWT授权过滤器。

我有实现UserDetails的自定义用户对象,我的用户服务也扩展了UserDetailsService。但是当我这样做时:

Usuario principal = (Usuario) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

Principal只是一个字符串(用户名),而不是我的用户对象。

这是我的配置:

SecurityConfig:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final LdapProperties ldapProperties;
    private final LdapUserMapper ldapUserMapper;
    private final UserService userService;


    public SecurityConfig(LdapProperties ldapProperties, LdapUserMapper ldapUserMapper, UserService userService) {
        this.ldapProperties = ldapProperties;
        this.ldapUserMapper = ldapUserMapper;
        this.userService = userService;
    }


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

        // Entry points
        http.authorizeRequests()
                .antMatchers(HttpMethod.POST, "/login").permitAll()
                .antMatchers(HttpMethod.GET, "/v2/api-docs",
                        "/configuration/ui",
                        "/swagger-resources",
                        "/configuration/security",
                        "/swagger-ui.html",
                        "/webjars/**",
                        "/swagger-resources/**",
                        "/swagger-ui.html").permitAll()
                        //TODO review
                .anyRequest().authenticated();

//        JwtWebSecurityConfigurer... TODO ?

        // Filters
        http.addFilter(new AuthenticationFilter(authenticationManager()));  // ldap
        http.addFilter(new AuthorizationFilter(authenticationManager()));   // jwt
        http.cors();
        http.csrf().disable();

        // No session will be created or used by spring security
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        // Need to provide Authorization header
        http.httpBasic();

    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(ldapAuthenticationProvider());
        auth.userDetailsService(userService);
    }





    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration().applyPermitDefaultValues();
        corsConfiguration.setAllowedMethods(Arrays.asList(CorsConfiguration.ALL));
        //TODO configure properly
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return source;
    }


    @Bean
    public AbstractLdapAuthenticationProvider ldapAuthenticationProvider() {

        String urls = "";
        for (String url : ldapProperties.getUrls()) {
            urls += url + " ";
        }
        urls = urls.trim();

        ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(
                ldapProperties.getBaseEnvironment().get("domain"),
                urls,
                ldapProperties.getBase()
        );
        provider.setUserDetailsContextMapper(ldapUserMapper); 
        provider.setConvertSubErrorCodesToExceptions(true);   
        // comment to connect as anonymous
        provider.authenticate(
                new UsernamePasswordAuthenticationToken(ldapProperties.getUsername(), ldapProperties.getPassword())
        );
        return provider;
    }
}

LdapUserMapper:

@Component
public class LdapUserMapper implements UserDetailsContextMapper {

    private final UserService userService;

    @Autowired
    public LdapUserMapper(UserService userService) {
        this.userService = userService;
    }


    @Override
    public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {

        Usuario result = (Usuario) userService.loadUserByUsername(username);
        //TODO compare roles ? set bloqueado ? ...
        return result;
    }

    @Override
    public void mapUserToContext(UserDetails userDetails, DirContextAdapter dirContextAdapter) {

    }
}

1 个答案:

答案 0 :(得分:0)

这是我的授权过滤器。

    @Override
    protected void doFilterInternal(HttpServletRequest req,
                                    HttpServletResponse res,
                                    FilterChain chain) throws IOException, ServletException {

        String token = req.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            token = token.replace("Bearer ", "");
            Authentication authentication = getAuthentication(token);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }

        chain.doFilter(req, res);
    }

    private UsernamePasswordAuthenticationToken getAuthentication(final String token) {

        try {
            DecodedJWT decodedToken = JWT.require(Algorithm.HMAC512(jwtSecret)).build().verify(token);
            String username = decodedToken.getSubject();
            return new UsernamePasswordAuthenticationToken(username , null, new ArrayList<>());
        } catch (JWTVerificationException ex) {
            log.error(ex.getMessage());
        }

        return null;
    }

我不知道我只是将用户名作为Principal对象传递。所以我将其更改为:

Usuario usuario = (Usuario) userService.loadUserByUsername(decodedToken.getSubject());

我也删除了

auth.userDetailsService(userService);

来自AuthenticationManagerBuilder配置。错了我的身份验证提供程序是LDAP,而不是数据库。