springsecurity的java配置

原文 https://blog.csdn.net/chemmuxin1993/article/details/53019889

Java 配置

在Spring 3.1中向Spring框架添加了对Java配置的常规支持。 自Spring Security 3.2以来,一直有Spring Security Java配置支持,使用户能够轻松地配置Spring Security而不使用任何XML。 

Spring Security提供了许多以-j结尾的示例应用程序,演示了使用Spring Security Java配置。

初识 Java 配置

第一步是创建我们的Spring Security Java配置。 配置创建一个名为springSecurityFilterChain的Servlet过滤器,它负责应用程序中的所有安全性(保护应用程序URL,验证提交的用户名和密码,重定向到登录表单等)。 你可以在下面找到Spring Security Java配置的最基本的例子:

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("cmx").password("123").roles("USER");
    }
}

 HttpSecurity

到目前为止,我们的WebSecurityConfig只包含有关如何验证我们的用户的信息。 Spring Security知道我们想要求所有用户进行身份验证? Spring Security知道我们要支持基于表单的身份验证? 其原因是WebSecurityConfigurerAdapterconfigure(HttpSecurity http)方法中提供了一个默认配置,如下所示:

protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .and()
            .httpBasic();
}
  • 上面的默认配置:
  • 确保对我们的应用程序的任何请求需要用户进行身份验证
  • 允许用户使用基于表单的登录进行身份验证
  • 允许用户使用HTTP Basic进行身份验证

您会注意到,此配置与XML命名空间配置非常相似:

<http>
    <intercept-url pattern="/**" access="authenticated"/>
    <form-login />
    <http-basic />
</http>
  • 关闭XML标签的Java配置等同于使用和()方法表示,这允许我们继续配置父代。 如果你读的代码,这也有意义。 我想配置授权的请求并配置表单登录和配置HTTP基本认证。 但是,Java配置具有不同的默认URL和参数。 创建自定义登录页面时请记住这一点。 结果是我们的URL更加RESTful。 此外,它不是很明显,我们使用Spring Security有助于防止信息泄漏。 例如:

Java配置和表单登录

您可能想知道当提示登录时登录表单来自哪里,因为我们没有提到任何HTML文件或JSP。 由于Spring Security的默认配置没有为登录页面显式设置URL,Spring Security会根据启用的功能自动生成一个URL,并使用处理提交的登录的URL的标准值,用户将使用的默认目标URL 发送到登录后等等。 虽然自动生成的登录页面方便快速启动和运行,但大多数应用程序想要提供自己的登录页面。 为此,我们可以更新我们的配置,如下所示:

protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/login") //1
            .permitAll(); //2
}
  •  

1 更改配置以指定login页面
2 我们必须授予所有用户(即未经身份验证的用户)对我们登录页面的访问权限。 formLogin().permitAll()方法允许向所有用户授予与基于表单的登录相关联的所有URL的访问权限

使用JSP实现的用于当前配置的示例登录页面如下所示:

下面的登录页面代表我们当前的配置。如果某些默认设置不能满足我们的需要,我们可以轻松修改我们的配置。

<c:url value="/login" var="loginUrl"/>
<form action="${loginUrl}" method="post">  //1
    <c:if test="${param.error != null}">  //2
        <p>
            Invalid username and password.
        </p>
    </c:if>
    <c:if test="${param.logout != null}">  //3
        <p>
            You have been logged out.
        </p>
    </c:if>
    <p>
        <label for="username">Username</label>
        <input type="text" id="username" name="username"/>  //4
    </p>
    <p>
        <label for="password">Password</label>
        <input type="password" id="password" name="password"/>  //5
    </p>
    <input type="hidden"  //6
        name="${_csrf.parameterName}"
        value="${_csrf.token}"/>
    <button type="submit" class="btn">Log in</button>
</form>

1 尝试对 /login 发送post请求以验证用户

2 如果查询参数 param.error 存在,则验证失败

3 如果查询参数 param.logout 存在,则注销成功

4 用户名必须以 username 为http请求参数

5 密码必须以 password 为http请求参数

6 这部分我们必须在第18.4.3节“包括CSRF令牌”中了解更多,请参阅第18章,跨站点请求伪造(CSRF)部分的参考

验证请求

我们的示例只需要对用户进行身份验证,并且对我们的应用程序中的每个网址都这样做。我们可以通过向我们的http.authorizeRequests()方法添加多个子节点来指定我们的URL的自定义要求。例如:

protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()  //1
            .antMatchers("/resources/**", "/signup", "/about").permitAll()  //2
            .antMatchers("/admin/**").hasRole("ADMIN")  //3
            .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")  //4
            .anyRequest().authenticated()  //5
            .and()
        // ...
        .formLogin();
}

1http.authorizeRequests()方法有多个子节点,每个匹配器都按它们声明的顺序考虑

2 我们指定了多个用户可以访问的网址格式。具体来说,如果网址以”/resources/”开头,等于”/signup”或等于”/about”,则任何用户都可以访问请求。

3 以”/admin/”开头的任何网址将被重新分配给具有角色”ROLE_ADMIN”的用户。你会注意到,由于我们调用了hasRole方法,我们不需要指定”ROLE_”前缀

4 以”/db/”开头的任何URL都要求用户同时拥有”ROLE_ADMIN”和”ROLE_DBA”。 你会注意到,由于我们使用hasRole表达式,我们不需要指定”ROLE_”前缀

5 任何尚未匹配的URL只需要对用户进行身份验证

注销登录

使用WebSecurityConfigurerAdapter时,会自动应用注销功能。 默认情况下,访问URL /logout将通过以下方式记录用户:

  • 使HTTP session无效
  • 清除配置的任何RememberMe身份验证
  • 清除 SecurityContextHolder
  • 跳转至 /login?logout

与配置登录功能类似,您还可以使用各种选项进一步自定义您的注销要求:

protected void configure(HttpSecurity http) throws Exception {
    http
        .logout()  //1
            .logoutUrl("/my/logout")  //2
            .logoutSuccessUrl("/my/index")  //3
            .logoutSuccessHandler(logoutSuccessHandler)  //4
            .invalidateHttpSession(true)  //5
            .addLogoutHandler(logoutHandler)  //6
            .deleteCookies(cookieNamesToClear)  //7
            .and()
        ...
}

1 提供注销支持。这在使用WebSecurityConfigurerAdapter时自动应用。

2 触发注销的URL(默认为/logout)。如果启用CSRF保护(默认),则请求也必须是POST。有关信息,请参阅JavaDoc

3 发生注销后重定向到的URL。默认值为/login?logout。有关信息,请参考JavaDoc。

4 让我们指定一个自定义LogoutSuccessHandler。如果指定此参数,将忽略logoutSuccessUrl()。有关信息,请参阅JavaDoc。

5 指定在注销时是否使HttpSession无效。 默认情况下是这样。 在封底下配置SecurityContextLogoutHandler。 有关信息,请参阅JavaDoc。

6 添加LogoutHandler。默认情况下,SecurityContextLogoutHandler作为最后一个LogoutHandler添加。

7 允许指定在注销成功时要删除的Cookie的名称。这是一个显式添加CookieClearingLogoutHandler的快捷方式。

当然,注销也可以使用XML命名空间符号进行配置。有关更多详细信息,请参阅Spring Security XML命名空间部分中的注销元素的文档。

通常,为了定制注销功能,您可以添加LogoutHandler/LogoutSuccessHandler实现。对于许多常见的情况,当使用流利的API时,这些处理程序应用在封面下

LogoutHandler

通常,LogoutHandler实现指示能够参与注销处理的类。它们将被调用来执行必要的清理。因此,他们不应该抛出异常。提供了各种实现:

有关详细信息,请参见第17.4节“Remember-Me接口和实现”。

并非直接提供LogoutHandler实现,流式API还提供了快捷方式,提供了相应的LogoutHandler实现。 例如。 deleteCookies()允许指定在注销成功时要删除的一个或多个cookie的名称。 与添加CookieClearingLogoutHandler相比,这是一个快捷方式。

登录成功句柄

LogoutSuccessHandler在LogoutFilter成功注销后被调用,以处理例如。 重定向或转发到适当的目的地。 注意,该接口几乎与LogoutHandler相同,但可能引发异常。

提供以下实现:

如上所述,您不需要直接指定SimpleUrlLogoutSuccessHandler。相反,流利的API通过设置logoutSuccessUrl()提供了一个快捷方式。 这将在下面设置SimpleUrlLogoutSuccessHandler。提供的URL将在发生注销后重定向到。 默认值为/login?logoutHttpStatusReturningLogoutSuccessHandler在REST API类型场景中很有趣。 成功注销后,此LogoutSuccessHandler不会重定向到URL,而是允许您提供要返回的纯HTTP状态代码。 如果未配置,默认情况下将返回状态代码200。

认证

到目前为止,我们只看了一下最基本的认证配置。让我们来看看一些稍微更高级的配置认证选项。

内存认证

我们已经看到了为单个用户配置内存身份验证的示例。以下是配置多个用户的示例:

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

JDBC 认证

您可以找到对基于JDBC的身份验证的更新。下面的示例假设您已经在应用程序中定义了一个DataSource。 jdbc-javaconfig示例提供了使用基于JDBC的身份验证的完整示例。

@Autowired
private DataSource dataSource;

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth
        .jdbcAuthentication()
            .dataSource(dataSource)
            .withDefaultSchema()
            .withUser("user").password("password").roles("USER").and()
            .withUser("admin").password("password").roles("USER", "ADMIN");
}

LDAP 认证

您可以找到更新以支持基于LDAP的身份验证。 ldap-javaconfig示例提供了使用基于LDAP的身份验证的完整示例。

@Autowired
private DataSource dataSource;

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth
        .ldapAuthentication()
            .userDnPatterns("uid={0},ou=people")
            .groupSearchBase("ou=groups");
}12345678910

上面的示例使用以下LDIF和嵌入式Apache DS LDAP实例。

dn: ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: groups

dn: ou=people,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: people

dn: uid=admin,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Rod Johnson
sn: Johnson
uid: admin
userPassword: password

dn: uid=user,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Dianne Emu
sn: Emu
uid: user
userPassword: password

dn: cn=user,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfNames
cn: user
uniqueMember: uid=admin,ou=people,dc=springframework,dc=org
uniqueMember: uid=user,ou=people,dc=springframework,dc=org

dn: cn=admin,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfNames
cn: admin
uniqueMember: uid=admin,ou=people,dc=springframework,dc=org

AuthenticationProvider

您可以通过将自定义AuthenticationProvider作为bean公开来定义自定义认证。例如,以下将自定义认证,假设SpringAuthenticationProvider实现AuthenticationProvider:


  这仅在未填充AuthenticationManagerBuilder时使用


@Bean
public SpringAuthenticationProvider springAuthenticationProvider() {
    return new SpringAuthenticationProvider();
}

UserDetailsService

您可以通过将自定义UserDetailsService作为bean公开来定义自定义认证。例如,以下将自定义认证,假设SpringDataUserDetailsService实现UserDetailsService:


  这仅在未填充AuthenticationManagerBuilder且未定义AuthenticationProviderBean时使用。


@Bean
public SpringDataUserDetailsService springDataUserDetailsService() {
    return new SpringDataUserDetailsService();
}

您还可以通过将PasswordEncoder公开为bean来自定义密码的编码方式。例如,如果使用bcrypt,您可以添加一个bean定义,如下所示:

@Bean
public BCryptPasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

猜你喜欢

转载自blog.csdn.net/asdfsadfasdfsa/article/details/83421780