【问题标题】:Spring Boot Security Ldap Rest ControllerSpring Boot 安全 Ldap Rest 控制器
【发布时间】:2016-09-18 17:12:17
【问题描述】:

我目前正在使用 Spring Security Ldap 实现 RestControllers。

登录成功,返回用户信息。

问题来了,当 Angular 前端想要调用我的 Rest api 时,安全返回未授权状态。 (不应该像我应该登录的那样)

我是 Spring Security 的新手,所以我的配置中可能缺少一些简单的东西 :)

这是一些截图和配置代码示例(出于保密目的,我从截图中删除了一些数据):

GetDocuments Unauthorized

GetDocuments unauthorised Details

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
@ComponentScan("com.*")
@PropertySource(value= {"classpath:application.properties"})
public class LdapSecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    private HttpAuthenticationEntryPoint authenticationEntryPoint;
    @Autowired
    private AuthSuccessHandler authSuccessHandler;
    @Autowired
    private AuthFailureHandler authFailureHandler;
    @Autowired
    private HttpLogoutSuccessHandler logoutSuccessHandler;


    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    @Override
    public UserDetailsService userDetailsServiceBean() throws Exception {
        return super.userDetailsServiceBean();
    }

    @Bean
    public AuthenticationProvider authenticationProvider() throws Exception {

        LdapAuthenticationProvider ldapAuthenticationProvider = new LdapAuthenticationProvider(getBindAuthenticator());
        ldapAuthenticationProvider.setUserDetailsContextMapper(new UserDetailsContextMapperImpl());


        return ldapAuthenticationProvider;
    }

    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

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

                http.authenticationProvider(authenticationProvider())
                    .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
                .and()
                    .csrf().disable()
                    .addFilterBefore(new CORSFilter(), ChannelProcessingFilter.class)
                    .authorizeRequests().antMatchers(authorizeRequestsCurrentUser).permitAll()
                .and()
                    .authorizeRequests().anyRequest().authenticated()
                .and().rememberMe()
                .and()
                    .formLogin()
                    .permitAll()
                    .loginProcessingUrl(loginProcessingUrl)
                    .usernameParameter(userNameParameter)
                    .passwordParameter(userPasswordParameter)
                    .successHandler(authSuccessHandler)
                    .failureHandler(authFailureHandler)
                .and()
                    .logout().permitAll()
                    .deleteCookies("JSESSIONID")
                    .logoutRequestMatcher(new AntPathRequestMatcher(logoutRequestMatcher, RequestMethod.GET.name()))
                    .logoutSuccessHandler(logoutSuccessHandler)
                    .logoutSuccessUrl(logoutSuccessUrl)
                    .clearAuthentication(true)
                .and()
                    .sessionManagement()
                    .maximumSessions(1);
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

            auth.eraseCredentials(false).authenticationProvider(authenticationProvider()).ldapAuthentication()
                .userSearchFilter(ldapUserSearchFilter)
                .groupSearchBase(ldapGroupSearchBase)
                .userDetailsContextMapper(new UserDetailsContextMapperImpl())
                .contextSource(getLdapContextSource());
    }

    private BindAuthenticator getBindAuthenticator()throws Exception{
        LdapContextSource contextSource = getLdapContextSource();

        String searchFilter=ldapSearchfilter;
        FilterBasedLdapUserSearch userSearch=new FilterBasedLdapUserSearch(ldapSearchBase, searchFilter,contextSource);
        userSearch.setSearchSubtree(true);


        BindAuthenticator bindAuthenticator = new BindAuthenticator(contextSource);
        bindAuthenticator.setUserSearch(userSearch);
        bindAuthenticator.afterPropertiesSet();

        return bindAuthenticator;
    }

    private LdapContextSource getLdapContextSource() throws Exception {
        LdapContextSource cs = new LdapContextSource();
        cs.setUrl(ldapUrl);
        cs.setBase(ldapBase);
        cs.setUserDn(ldapUserDn);
        cs.setPassword(ldapPassword);
        cs.setPooled(true);
        cs.afterPropertiesSet();
        return cs;
    }

}



@Component
@Log4j
public class AuthSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
    private final ObjectMapper mapper;

    @Autowired
    AuthSuccessHandler(MappingJackson2HttpMessageConverter messageConverter) {
        this.mapper = messageConverter.getObjectMapper();
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {

        LdapUser authUser = (LdapUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        MyUser user = new MyUser();
        user.setUsername(authUser.getUsername());
        user.setPassword(cred);

        // set our response to OK status
        response.setStatus(HttpServletResponse.SC_OK);
        response.setContentType(MediaType.APPLICATION_JSON_VALUE+"; charset=UTF-8");

        PrintWriter writer = response.getWriter();
        mapper.writeValue(writer, authUser);
        writer.flush();
    }
}




public class CORSFilter  implements Filter{
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS,"true");
        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "POST, GET, OPTIONS, DELETE");
        response.setHeader(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "3600");
        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "x-requested-with");
        chain.doFilter(request, response);
    }

    public void destroy() {}
}



@Component
public class UserDetailsContextMapperImpl extends LdapUserDetailsMapper {

    @Override
    public UserDetails mapUserFromContext(DirContextOperations ctx, String username,
                                          Collection<? extends GrantedAuthority> authorities) {
        UserDetails userDetails= super.mapUserFromContext(ctx,username,authorities);
        String fullName = ctx.getStringAttribute("givenName");
        String email = ctx.getStringAttribute("mail");
        return new LdapUser((LdapUserDetails)userDetails,fullName,email);
    }
}


@Log4j
@CrossOrigin
@RestController
@ComponentScan("com.*")
@RequestMapping(value = "${config.rest.uri.entry.path}", produces = MediaType.APPLICATION_JSON_VALUE)
public class DashboardController {

    @Autowired
    IDashboardService dashboardService;

    @RequestMapping(value = "${config.rest.uri.dashboard.documents}",method = RequestMethod.GET,produces = MediaType.APPLICATION_JSON_VALUE)
    public Result<List<DashboardDocument>> getDocumentList(@RequestParam(value="username") String username){


     ----------------

        return result;
    }
}

【问题讨论】:

    标签: spring spring-security spring-boot spring-ldap spring-restcontroller


    【解决方案1】:

    您解决了 2 年以来的问题吗? :-p

    我想做同样的事情,我对你的代码很感兴趣,你应该分享吗?

    否则,我有办法,将其添加到您的 onAuthenticationSuccess 中(可在此处找到:https://www.baeldung.com/securing-a-restful-web-service-with-spring-security):

        SavedRequest savedRequest
          = requestCache.getRequest(request, response);
    
        if (savedRequest == null) {
            clearAuthenticationAttributes(request);
            return;
        }
        String targetUrlParam = getTargetUrlParameter();
        if (isAlwaysUseDefaultTargetUrl()
          || (targetUrlParam != null
          && StringUtils.hasText(request.getParameter(targetUrlParam)))) {
            requestCache.removeRequest(request, response);
            clearAuthenticationAttributes(request);
            return;
        }
    
        clearAuthenticationAttributes(request);
    

    【讨论】:

      【解决方案2】:

      为了让您的 api 知道用户已通过身份验证,请求必须包含身份验证信息。通常它会在请求标头中。 This spring 教程展示了如何使用 Angular 来传递身份验证信息。请注意,这仅支持基本身份验证。

      【讨论】:

      • 感谢您的回复,我进行了更多调查,当我查看 Spring Security 调试日志时,我感觉 Security 上下文没有保存,但我不知道为什么。我会发布日志。
      【解决方案3】:

      这里是 spring 安全日志:

      spring security logs

      【讨论】:

        【解决方案4】:

        也许您已经找到了答案,但为了完整起见,这里是导致您的 restcontrollers 请求访问被拒绝的一行代码。在您的配置中,您使用.formLogin() 作为将凭证传输到您的休息控制器的一种方式,但休息控制器是无会话的,它不会从您的会话中获取任何内容。您将需要一种不同的方式将您的凭证从您的客户端传输到其余控制器。一种方法是将.formLogin() 更改为httpBasic()

        【讨论】:

          猜你喜欢
          • 2017-07-02
          • 2015-07-02
          • 2016-06-03
          • 1970-01-01
          • 2019-11-24
          • 1970-01-01
          • 1970-01-01
          • 2017-06-08
          • 1970-01-01
          相关资源
          最近更新 更多