【问题标题】:Spring default Authentication internal workingSpring默认身份验证内部工作
【发布时间】:2017-05-07 05:21:37
【问题描述】:

我刚开始学习 Spring 和 Spring Security,并通过阅读 Spring Security 文档创建了一个简单的项目。我完成了以下基于 java 的配置。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
            .withUser("admin")
            .password("nimda")
            .roles("ADMIN");
    }

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

        http.authorizeRequests()
            .antMatchers("/").permitAll() 
            .antMatchers("/admin**").access("hasRole('ADMIN')")
            .and().formLogin();

        http.csrf().disable();
    }
}

当我选择“/admin”时,它会将我重定向到我知道 spring 使用此默认配置生成的登录页面,登录后它将显示登录页面。现在我的问题是:登录表单已发布到“/ login”,我没有定义任何“AuthenticationManager”和“UserDetailService”,我在自定义配置文档中阅读了这些信息,那么spring 如何发布表单并执行登录过程?基本上我想知道这个默认登录过程的内部工作的一些细节。

【问题讨论】:

标签: java spring spring-mvc spring-security


【解决方案1】:

当您使用 *ConfigurerAdapter 类时,在上下文加载期间会发生很多事情。 Spring 会检查你是否定义了一个 AuthenticationManager,如果没有,它会创建一个默认的。

如果您真的对神奇配置步骤中发生的事情感兴趣,您可能需要查看源代码。例如,如果您查看 WebSecurityConfigurerAdapter.getHttp(),您可以看到它调用 authenticationManager() 来构造这个 bean。

protected AuthenticationManager authenticationManager() throws Exception {
    if (!authenticationManagerInitialized) {
        configure(localConfigureAuthenticationBldr);
        if (disableLocalConfigureAuthenticationBldr) {
            authenticationManager = authenticationConfiguration
                    .getAuthenticationManager();
        }
        else {
            authenticationManager = localConfigureAuthenticationBldr.build();
        }
        authenticationManagerInitialized = true;
    }
    return authenticationManager;
}

在过去,您必须自己创建所有 bean 并将它们连接在一起,因此我们更加了解事物是如何组合在一起的。现在您要么必须阅读源代码,要么从指南中复制,并希望您不要犯任何错误。

调试提示:这几天看context加载后存在的beans,然后回去在AuthenticationManager实现的构造函数中设置断点,就可以看到调用堆栈以及初始化如何工作。

【讨论】:

  • 感谢您的宝贵时间。我有带有 URL “/login” 的 POST 方法,但是 spring 忽略了它并执行了他自己的默认实现。我需要调用我自己的登录后控制器方法。
  • 你自己的登录控制器是什么意思? Spring security 有一个 AuthenticationManager,它通常使用一个或多个 AuthenticationProvider 实现来配置。如果您需要执行自定义操作,您可能需要添加自己的 AuthenticationProvider 并实现 authenticate(Authentication) 方法。此时 UsernamePasswordAuthenticationToken 已经创建,您可以检查用户在登录表单中输入的内容。
  • 我的意思是登录表单发布网址是“/login”,我有一个带有“/login”的控制器方法,当表单发布时该方法没有命中。所以这意味着 spring security 将表单数据直接提供给安全的东西,并且不会影响我的控制器方法。
【解决方案2】:

这是您要查找的代码,您可以实现自己的自定义 AuthenticationProvider,而不是使用构建器来构建内存中的用户详细信息源。

public void configure(AuthenticationManagerBuilder auth) throws Exception {

    auth.authenticationProvider(new AuthenticationProvider() {
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            String password = (String) authentication.getPrincipal();
            String userName = (String) authentication.getCredentials();

            if ("user".equals(userName) && "password".equals(password)) {
                authentication = new UsernamePasswordAuthenticationToken(userName, password, Lists.newArrayList(new SimpleListProperty<GrantedAuthority>(null, "USER")));
                return authentication;
            }
            throw new BadCredentialsException("Incorrect username or password.");
        }

        @Override
        public boolean supports(Class<?> authentication) {
            return true;
        }
    });
}

请注意,您可以创建自己的身份验证实现以防需要添加其他信息,或者您可以使用每个身份验证都可以拥有的 details 属性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-13
    • 2017-09-11
    • 2013-12-15
    • 2021-12-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多