Spring Boot:2个不同的登录页面,包含2个网址

时间:2016-10-29 14:06:10

标签: java spring-mvc spring-security spring-boot

我有一个Spring Boot应用程序。我有2个登录页面,用于系统中的2组不同用户。

  1. 任何以/expert开头的网址,用户都应具有EXPERTADMIN的角色。用户使用表单登录登录系统,登录页面路径为/login

  2. 对于某些网址,例如cssjs等,不需要进行身份验证。

  3. 对于所有其他URL,用户不需要特殊角色,身份验证就足够了。用户的登录页面应为/loginTwo

  4. 我查看了this stackoverflow问题和this文档来实现这一点。但是,当我访问包含/expert的网址时,我会转到登录页面/loginTwo,而不是/login

    以下是我的代码:

    @Autowired
    @Qualifier("userService")
    UserDetailsService userDetailsService;
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        PasswordEncoder encoder = new Md5PasswordEncoder();
        return encoder;
    }
    
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }
    
    @Configuration
    @Order(1)
    public static class ExpertWebSecurity extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
    
            http
                .authorizeRequests()
                    .antMatchers("/login/**").permitAll();
            http
                .antMatcher("/expert/**")
                .authorizeRequests()
                    .anyRequest().access("hasRole('ROLE_ADMIN') or hasRole('ROLE_EXPERT')")
                    .and()
                .formLogin()
                    .loginPage("/login").permitAll();
        }
    }
    
    @Configuration
    public static class StudentWebSecurity extends WebSecurityConfigurerAdapter{
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            System.out.println("Here in stu");
    
            http
                .authorizeRequests()
                    .antMatchers("/css/**,/js/**").permitAll()
                    .antMatchers("/error/**").permitAll()
                    .antMatchers("/student/**").permitAll()
                    .antMatchers("/filter/**").permitAll()
                    .antMatchers("/loginTwo").permitAll()
                    .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_EXPERT')")
                    .antMatchers("/").permitAll()
                    .anyRequest().authenticated()
                    .and()
                .csrf();
            http
                .formLogin()
                    .loginPage("/loginTwo").permitAll()
                    .and()
                .logout().permitAll();
            http
                .sessionManagement()
                    .maximumSessions(20)
                    .expiredUrl("/loginTwo")
                    .maxSessionsPreventsLogin(false);
            http
                .headers().addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN));
        }
    }
    

    请你帮我解决这个问题。

1 个答案:

答案 0 :(得分:0)

您需要为每个不同的端点添加不同的身份验证过滤器。

对于HttpSecurity,您可以定义类似的内容,为构造函数提供UserDetailsService并传递身份验证管理器:

  .addFilterBefore(new FirstLoginFilter("/api/login/first", userDetailsService, authenticationManager()), UsernamePasswordAuthenticationFilter.class)
  .addFilterBefore(new SecondLoginFilter("/api/login/second", userDetailsService, authenticationManager()), UsernamePasswordAuthenticationFilter.class)
  .addFilterBefore(new AdminLoginFilter("/api/login/admin", userDetailsService, authenticationManager()), UsernamePasswordAuthenticationFilter.class)

过滤器的实现看起来像这样。

让我们从抽象认证过滤器开始,它是上述所有过滤器的父级:

public abstract class LoginFilter extends AbstractAuthenticationProcessingFilter {
    protected final SimpleUserDetailsService userService;

    public LoginFilter(String pattern, SimpleUserDetailsService userService, AuthenticationManager authManager) {
        super(new AntPathRequestMatcher(pattern));
        this.userService = userService;
        this.setAuthenticationManager(authManager);
        this.setAuthenticationSuccessHandler(new FormAuthenticationSuccessHandler());
        this.setAuthenticationFailureHandler(new FormAuthenticationFailureHandler());
    }

    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws ServletException {
        User authenticatedUser = this.userService.loadUserByUsername(authentication.getName());
        UserAuthentication userAuthentication = new UserAuthentication(authenticatedUser);
        SecurityContextHolder.getContext().setAuthentication(userAuthentication);
    }
}

例如,实际过滤器的一个实现:

public class FirstLoginFilter extends LoginFilter {
    public FirstLoginFilter(String pattern, SimpleUserDetailsService userDetailsService, AuthenticationManager authManager) {
        super(pattern, userDetailsService, authManager);
    }

    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        User user = (User)(new ObjectMapper()).readValue(request.getInputStream(), User.class);
        UsernamePasswordAuthenticationToken loginToken = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
        Authentication authentication = this.getAuthenticationManager().authenticate(loginToken);
        if(!Role.isRolePresent(authentication.getAuthorities(), Role.YOUR_ROLE)) {
            throw new BadCredentialsException("Bad credentials");
        } else {
            return authentication;
        }
    }
}

我的示例使用无状态身份验证机制,因此您需要相应地修改过滤器。正如我从您的初始示例中看到的那样,您正在使用会话,因此实际上它应该更容易,因为它已经内置于Spring Security中

希望它有所帮助。