Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/385.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Spring Security 3.2.1具有不同WebSecurity配置适配器的多个登录表单_Java_Spring_Spring Mvc_Spring Security - Fatal编程技术网

Java Spring Security 3.2.1具有不同WebSecurity配置适配器的多个登录表单

Java Spring Security 3.2.1具有不同WebSecurity配置适配器的多个登录表单,java,spring,spring-mvc,spring-security,Java,Spring,Spring Mvc,Spring Security,我将SpringSecurity3.2.1.RELEASE与SpringMVC4.0.4.RELEASE一起使用 我正在尝试为一个web应用程序设置Spring安全性,该应用程序将有两个不同的登录条目页面。我需要的网页是不同的,因为他们将被样式和访问不同 第一个登录页面用于管理员用户,并保护管理员页面/Admin/** 第二个登录页面用于客户用户,并保护客户页面/Customer/** 我试图设置WebSecurity ConfigureAdapter的两个子类来配置各个HttpSecurity

我将SpringSecurity3.2.1.RELEASE与SpringMVC4.0.4.RELEASE一起使用

我正在尝试为一个web应用程序设置Spring安全性,该应用程序将有两个不同的登录条目页面。我需要的网页是不同的,因为他们将被样式和访问不同

第一个登录页面用于管理员用户,并保护管理员页面/Admin/**

第二个登录页面用于客户用户,并保护客户页面/Customer/**

我试图设置WebSecurity ConfigureAdapter的两个子类来配置各个HttpSecurity对象

CustomPerformLoginWebSecurity正在保护客户页面,并在未经授权的情况下重定向到客户登录页面。 AdminFormLoginWebSecurity在未经授权的情况下保护重定向到管理员登录页面的管理员页面

不幸的是,似乎只有第一个配置被强制执行。我想我错过了一些额外的东西,使这两个工作

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    public void registerGlobalAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .inMemoryAuthentication()
                .withUser("customer").password("password").roles("CUSTOMER").and()
                .withUser("admin").password("password").roles("ADMIN");
    }

    @Configuration
    @Order(1)
    public static class CustomerFormLoginWebSecurity extends WebSecurityConfigurerAdapter {

        @Override
        public void configure(WebSecurity web) throws Exception {
            web
                    .ignoring()
                    .antMatchers("/", "/signin/**", "/error/**", "/templates/**", "/resources/**", "/webjars/**");
        }

        protected void configure(HttpSecurity http) throws Exception {
            http
                    .csrf().disable()
                    .authorizeRequests()
                    .antMatchers("/customer/**").hasRole("CUSTOMER")
                    .and()
                    .formLogin()
                    .loginPage("/customer_signin")
                    .failureUrl("/customer_signin?error=1")
                    .defaultSuccessUrl("/customer/home")
                    .loginProcessingUrl("/j_spring_security_check")
                    .usernameParameter("j_username").passwordParameter("j_password")
                    .and()
                    .logout()
                    .permitAll();

            http.exceptionHandling().accessDeniedPage("/customer_signin");
        }
    }

    @Configuration
    public static class AdminFormLoginWebSecurity extends WebSecurityConfigurerAdapter {
        @Override
        public void configure(WebSecurity web) throws Exception {
            web
                    .ignoring()
                    .antMatchers("/", "/signin/**", "/error/**", "/templates/**", "/resources/**", "/webjars/**");
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .csrf().disable()
                    .authorizeRequests()
                    .antMatchers("/admin/**").hasRole("ADMIN")
                    .and()
                    .formLogin()
                    .loginPage("/admin_signin")
                    .failureUrl("/admin_signin?error=1")
                    .defaultSuccessUrl("/admin/home")
                    .loginProcessingUrl("/j_spring_security_check")
                    .usernameParameter("j_username").passwordParameter("j_password")
                    .and()
                    .logout()
                    .permitAll();

            http.exceptionHandling().accessDeniedPage("/admin_signin");
        }
    }

}

也许这篇文章可以帮助你:

这是一个不同版本的spring security,但问题是相同的:只采用第一个配置

通过更改两个登录页面之一的登录处理url,似乎已经解决了这个问题,但人们建议使用相同的url处理,但使用ViewResolver使用不同的布局。如果您使用相同的机制对用户进行身份验证(身份验证机制负责处理浏览器发送的凭据),则这是一种解决方案

这篇文章似乎还说,如果您更改了loginProcessingUrl,您将成功:

spring登录链中重定向到登录页面的组件是身份验证过滤器,使用
http.formLogin()
时插入的过滤器是
DefaultLoginPageGeneratingFilter

如果未提供登录页面url,此筛选器将重定向到登录url或生成默认的基本登录页面

然后,您需要的是一个定制的身份验证过滤器,它具有定义需要哪个登录页面的逻辑,然后将其插入到spring安全链中以代替单页面身份验证过滤器

考虑创建一个
TwoPageLoginAuthenticationFilter
,方法是子类化
DefaultLoginPageGeneratingFilter
并重写
getLoginPageUrl()
,如果这还不够,则复制代码并修改它以满足您的需要

此筛选器是一个
GenericFilterBean
,因此您可以这样声明它:

@Bean
public Filter twoPageLoginAuthenticationFilter() {
    return new TwoPageLoginAuthenticationFilter();
}
然后尝试只构建一个http配置,不要设置
formLogin()
,而是:

http.addFilterBefore(twoPageLoginAuthenticationFilter, ConcurrentSessionFilter.class);

这将在链中正确的位置插入两种形式的身份验证过滤器。

我为多个登录页面提供的解决方案涉及一个http身份验证,但我提供了自己的实现

  • AuthenticationEntryPoint
  • AuthenticationFailureHandler
  • LogoutSuccessHandler
我需要的是这些实现能够依赖于请求路径中的令牌进行切换

在我的网站中,url中带有客户令牌的页面受到保护,并要求用户在客户登录页面上以客户身份进行身份验证。 因此,如果要转到页面/客户/主页,则需要将我重定向到客户登录页面以首先进行身份验证。 如果我未能在客户签名上进行身份验证,则应将我返回给客户签名,并提供一个错误参数。以便显示消息。
当我成功通过客户身份验证并希望注销时,LogoutSuccessHandler应将我带回CUSTOMER_signin页面

我有一个类似的要求,管理员需要在管理员登录页面进行身份验证,才能访问url中带有管理员令牌的页面

首先,我定义了一个类,该类允许我获取令牌列表(每种类型的登录页面对应一个令牌)

PathTokenNotFoundException扩展AuthenticationException,以便您可以用常规方式处理它

public class PathTokenNotFoundException extends AuthenticationException {

   public PathTokenNotFoundException(String msg) {
       super(msg);
    }

    public PathTokenNotFoundException(String msg, Throwable t) {
       super(msg, t);
    }
}
接下来,我提供了一个
AuthenticationFailureHandler
的实现,它查看请求头中的referer url,以确定用户要指向哪个登录错误页面

@Component
public class PathUrlAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    private final PathTokens tokens;

    @Autowired
    public PathUrlAuthenticationFailureHandler(PathTokens tokens) {
        super();
        this.tokens = tokens;
    }

    /**
     * Performs the redirect or forward to the {@code defaultFailureUrl associated with this path} if set, otherwise returns a 401 error code.
     * <p/>
     * If redirecting or forwarding, {@code saveException} will be called to cache the exception for use in
     * the target view.
     */
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
                                    AuthenticationException exception) throws IOException, ServletException {
        setDefaultFailureUrl(getFailureUrlFromPath(request));
        super.onAuthenticationFailure(request, response, exception);

    }

    private String getFailureUrlFromPath(HttpServletRequest request) {
        String refererUrl = request.getHeader("Referer");
        if (tokens.isTokenInPath(refererUrl)) {
            return "/" + tokens.getTokenFromPath(refererUrl) + "_signin?error=1";
        }
        throw new PathTokenNotFoundException("Token not found in referer URL " + refererUrl + " when retrieving failureUrl for login form");
    }
}
最后一步是在安全配置中将它们连接在一起

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired PathLoginAuthenticationEntryPoint loginEntryPoint;

    @Autowired PathUrlAuthenticationFailureHandler loginFailureHandler;

    @Autowired
    PathUrlLogoutSuccessHandler logoutSuccessHandler;


    @Bean
    public PathTokens pathTokens(){
        return new PathTokens(Arrays.asList("customer", "admin"));
    }

    @Autowired
    public void registerGlobalAuthentication(
        AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
            .withUser("customer").password("password").roles("CUSTOMER").and()
            .withUser("admin").password("password").roles("ADMIN");
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web
            .ignoring()
            .antMatchers("/", "/signin/**", "/error/**", "/templates/**", "/resources/**", "/webjars/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
           http .csrf().disable()
            .authorizeRequests()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .antMatchers("/customer/**").hasRole("CUSTOMER")
            .and()
            .formLogin()
            .loginProcessingUrl("/j_spring_security_check")
            .usernameParameter("j_username").passwordParameter("j_password")
            .failureHandler(loginFailureHandler);

        http.logout().logoutSuccessHandler(logoutSuccessHandler);
        http.exceptionHandling().authenticationEntryPoint(loginEntryPoint);
        http.exceptionHandling().accessDeniedPage("/accessDenied");
    }
}
一旦你配置好了,你需要一个控制器来引导到实际登录页面。下面的Signincontroller检查queryString中是否有表示登录错误的值,然后设置用于控制错误消息的属性

@Controller
@SessionAttributes("userRoles")
public class SigninController {
    @RequestMapping(value = "customer_signin", method = RequestMethod.GET)
    public String customerSignin(Model model, HttpServletRequest request) {
        Set<String> userRoles = AuthorityUtils.authorityListToSet(SecurityContextHolder.getContext().getAuthentication().getAuthorities());
        model.addAttribute("userRole", userRoles);

        if(request.getQueryString() != null){
            model.addAttribute("error", "1");
        }
        return "signin/customer_signin";
    }


    @RequestMapping(value = "admin_signin", method = RequestMethod.GET)
    public String adminSignin(Model model, HttpServletRequest request) {
    Set<String> userRoles = AuthorityUtils.authorityListToSet(SecurityContextHolder.getContext().getAuthentication().getAuthorities());
        model.addAttribute("userRole", userRoles);
        if(request.getQueryString() != null){
            model.addAttribute("error", "1");
        }
        return "signin/admin_signin";
    }
}
@控制器
@SessionAttributes(“用户角色”)
公共类签名控制器{
@RequestMapping(value=“customer\u signin”,method=RequestMethod.GET)
公共字符串customerSignin(模型,HttpServletRequest){
设置userRoles=AuthorityUtils.authorityListToSet(SecurityContextHolder.getContext().getAuthentication().GetAuthories());
model.addAttribute(“userRole”,userRoles);
if(request.getQueryString()!=null){
model.addAttribute(“错误”,“1”);
}
返回“签到/客户签到”;
}
@RequestMapping(value=“admin\u signin”,method=RequestMethod.GET)
公共字符串adminSignin(模型,HttpServletRequest){
设置userRoles=AuthorityUtils.authorityListToSet(SecurityContextHolder.getContext().getAuthentication().GetAuthories());
model.addAttribute(“userRole”,userRoles);
if(request.getQueryString()!=null){
model.addAttribute(“错误”,“1”);
}
返回“登录/管理员登录”;
}
}

我也遇到了这个问题,发现我错过了第一个过滤部分

这个:

http.csrf().disable()
    .authorizeRequests()
    .antMatchers("/admin/**").hasRole("ADMIN")
应该是:

http.csrf().disable()
    .antMatcher("/admin/**")
    .authorizeRequests()
    .antMatchers("/admin/**").hasRole("ADMIN")
添加第一个筛选。antMatcher(“/admin/**”)将首先对其进行筛选,以便它将使用AdminFormLoginWebSecurity代替
@Controller
@SessionAttributes("userRoles")
public class SigninController {
    @RequestMapping(value = "customer_signin", method = RequestMethod.GET)
    public String customerSignin(Model model, HttpServletRequest request) {
        Set<String> userRoles = AuthorityUtils.authorityListToSet(SecurityContextHolder.getContext().getAuthentication().getAuthorities());
        model.addAttribute("userRole", userRoles);

        if(request.getQueryString() != null){
            model.addAttribute("error", "1");
        }
        return "signin/customer_signin";
    }


    @RequestMapping(value = "admin_signin", method = RequestMethod.GET)
    public String adminSignin(Model model, HttpServletRequest request) {
    Set<String> userRoles = AuthorityUtils.authorityListToSet(SecurityContextHolder.getContext().getAuthentication().getAuthorities());
        model.addAttribute("userRole", userRoles);
        if(request.getQueryString() != null){
            model.addAttribute("error", "1");
        }
        return "signin/admin_signin";
    }
}
http.csrf().disable()
    .authorizeRequests()
    .antMatchers("/admin/**").hasRole("ADMIN")
http.csrf().disable()
    .antMatcher("/admin/**")
    .authorizeRequests()
    .antMatchers("/admin/**").hasRole("ADMIN")