Spring Boot安全保护使用教程


在这篇文章中,我将解释Spring如何管理安全性。当然,我不会涵盖所有内容 - 安全问题将可以写成一本大书,但我们至少会看看如何保护网站。如何使用两个Java类及其HTML文件来保护您的网页。

Spring Boot实际上非常简单,因为我们只要使用Spring的启动器即可,启动器包括Web,Thymeleaf,当然还有Security。

这些启动器会打包在pom.xml文件中。

Thymeleaf 是与Spring无缝集成并创建网页模板的软件,它与JSP类似,但Thymeleaf是一个更加改进的版本。或者,更像JSF,更JavaEE一些。案例中使用它的HTML页面与Spring的类无缝集成。

如果我们要在网页中看到登录的用户名,就需要使用库安全的Thymeleaf for Spring。为此,我们将在pom.xml文件中包含以下行。


<dependency>
  <groupId> org.thymeleaf.extras <groupId/>
  <artifactId> thymeleaf-extras-springsecurity4 <artifactId/>
  <version> 3.0.3.RELEASE <version/>
<dependency/>


现在,我们开始声明我们的第一个类,我称之为 WebSecurityConfiguration.java:


@SpringBootApplication
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    public static void main (String [] args) {
            SpringApplication.run (WebSecurityConfiguration.class, args);
    }

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

    @Bean
    @Override
    public UserDetailsService userDetailsService() {
         UserDetails user = User.builder()(). Username("user").Password(passwordEncoder().Encode( "secret")).roles ( "USER") build().;
         UserDetails UserAdmin = User.builder(). Username(
"admin").Password(passwordEncoder().Encode( "secret")).roles ( "ADMIN") build().;
        return new InMemoryUserDetailsManager (user, UserAdmin);
    }

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

    @Override
    protected void set (http HttpSecurity) throws Exception {
        http
        .csrf().disable()
            .authorizeRequests()
            .antMatchers(
"/" "/ index", "/ webpublico"). permitAll()
            .antMatchers(
"/ webprivado"). authenticated()
            .antMatchers(
"/ webadmin"). hasRole ( "ADMIN"). and()
                .formLogin()
                .loginPage(
"/ login")
                .permitAll()
                .and()
                .logout()
// get method for I desabilitado CSRF
                .permitAll();
    }
}


标注@SpringBootApplication 和 @EnableWebSecurity。第一个希望使用Spring Boot必注;第二个是指定激活Web安全性; 老实说,这个标签不是必需的,Spring Boot非常聪明,因为我们已经看到了项目中引入了安全性包(在pom.xml中)。但它提供了进一步的清晰度,但是,尽管是多余的。


@SpringBootApplication
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {


现在,我们指定我们的类将继承自WebSecurityConfigurerAdapter,因为我们会覆盖该类的一些功能。因此,你需要了解Spring并查看是否存在类实现接口WebSecurityConfigurer,后者又实现接口WebSecurityConfigurerAdapter,如果有,则使用该接口的功能来配置安全应用程序。

如果我们有一个实现此接口的类,Spring就不会访问我们应用程序的任何页面,但不是很实用。


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


现在,我们需要编写一个函数 authenticationManagerBean 来返回负责管理身份验证的类(顾名思义)。重要的是要知道在哪里获取(注入)对象类型AuthenticationManager, 因为只有通过它你才能控制Spring的安全性。


@Bean
@Override
public UserDetailsService userDetailsService() {
 UserDetails user = User.builder()(). Username("user").Password(passwordEncoder().Encode( "secret")).roles ( "USER") build().;
 UserDetails UserAdmin = User.builder(). Username(
"admin").Password(passwordEncoder().Encode( "secret")).roles ( "ADMIN") build().;
 return new InMemoryUserDetailsManager (user, UserAdmin);
}

在userDetailsService,我们定义可以访问我们网站的用户。在这种情况下,我们创建了两个用户:user和admin,每个用户都有自己的密码和角色。角色名称USER和ADMIN可以自己定义,可以是你想要的任何字母。例如,USER_WITH_EYES - 事实是我们一旦使用该角色名,它必须与你定义的角色集合的角色名称逐个字母匹配。

另请注意,在这种情况下,密码是使用算法Bcrypt加密的。我们通过调用函数来完成此操作,该函数 passwordEncoder使用Spring @Bean 标签进行注释。

也就是说,Spring需要知道我们用来存储密码的加密系统,并且它寻找实现接口的对象 PasswordEncoder:

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


我想澄清一下,我们使用最简单的方法来声明用户并将其存储在内存中 InMemoryUserDetailsManager。在真实的程序中,它会使用JdbcUserDetailsManager,存储在数据库中。或者可能是包括实现接口UserDetailsManager的任何其他类, 如果我们使用LDAP服务可能会是LdapUserDetailsManager。


@Override
protected void set (http HttpSecurity) throws Exception {
   http.csrf().disable()
            .authorizeRequests()
            .antMatchers( "/" "/ index", "/ webpublico"). permitAll()
            .antMatchers(
"/ webprivado"). authenticated()
            .antMatchers(
"/ webadmin"). hasRole ( "ADMIN"). and()
                .formLogin()
                .loginPage(
"/ login")
                .permitAll()
                .and()
                .logout()
// get method for I desabilitado CSRF
                .permitAll();
}


由于我们需要定义应用程序的哪些部分将受到保护,因此角色必须具有访问其每个部分的权限。是的,是角色而非用户,因为正如我们之前所说,当您定义用户时,您必须分配一个角色。通常,过滤规则是适用于用户所属的组,要为每个资源设置权限,我们要在函数protected void configure(HttpSecurity http)中配置接受的对象HttpSecurity。

我将逐行解释在这个函数中做了什么:

csrf(). disable()
首先,我们正在研究CSRF禁用控制。CRSF代表 跨站点请求伪造, 禁用CRSF有副作用,可以使用HTTP GET请求执行会话注销,然后默认只能通过POST请求完成:

.authorizeRequests ().antMatchers("/","/ index", "/webpublico").permitAll ()

我们指定使用任何字符串“/”,“/ index”,“/ webpublico”等路由的URL将不具有安全性。每个人都可以访问。

antMatchers ("/webprivado").authenticated()
我们指定请求路径“/webprivado”需要用户进行身份验证才能访问,不需要指定属于什么角色。

.antMatchers("/webadmin").hasRole("ADMIN")
只有属于ADMIN角色的用户才能访问URL “/ webadmin”。

该函数antMatchers是可使用正则表达式,因此,例如,如果我们想要将规则应用于依赖于路由的所有规则,我们可以将此:

http.antMatchers(“/ users / **”).hasRole(“USER”)
指定访问URL是/users/XXX的任何请求只能是属于USER角色的用户发出的。

.formLogin().loginPage("/login").permitAll()
我们指定登录页面为“ / login ”并允许其访问所有人。

logout(). permitAll()
我们指定可让所有人访问​​退出页面。默认情况下,此页面由URL“ /logout ”响应。

我们已经定义了我们网站的安全性。现在,我们只要定义页面的入口点。完成类 WebController.java。


@Controller
public class WebController
{
@RequestMapping ({ "/", "index"})
public String start () {
return
"index";
}
@RequestMapping (
"/webprivado")
public private String () {
"Private" return;
}
@RequestMapping (
"/webpublico")
public String loginpub () {
"Public" return;
}
@RequestMapping (
"/webadmin")
public String admin () {
return
"admin";
}
@RequestMapping (
"/login")
public String login () {
return
"login";
}
}

如上所述,@Controller定义Web请求的入口点。

@RequestMapping来指定URL并由每个函数处理。因此,当对URL,“ / ”或“ /index ” 的请求时,将调用函数start。

返回的字符串将是Thymeleaf返回的模板,start函数将返回“index.html”模板,如下所示:


<! DOCTYPE html>
<Html xmlns = "http://www.w3.org/1999/xhtml" xmlns: th = "http://www.thymeleaf.org"
xmlns: sec =
"http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<Head>
<Title> Home Page </ title>
</ Head>
<Body>
<H1> Home Page </ h1>
<P> <a th:href=
"@{/webpublico}"> Click here to view a page </a> public. </ P>
<P> If you are a regular user clicks </a> <a th:href=
"@{/webprivado}"> here to view a private page </ p>
<P> If you are a regular administrator </a> click <a th:href=
"@{/webadmin}"> here to see the profile Administrator </ p>
<Div sec: Authorize =
"isAuthenticated ()">
Hello <span sec: authentication =
"name"> someone </ span>
<P> <a th:href=
"@{/logout}"> Disconnect </a> </ p>
</ Div>
</ Body>
</ Html>

它看起来像纯HTML?这是使用Thymeleaf标准HTML标记的优势之一。我不会在这里解释这个语言,但我将解释一些使用的标签:

<a th:href="@{/webpublico}">
创建指向“/webpublico” 的链接。这就像使用“tag <A href="/webpublico">。

<div sec: Authorize = "isAuthenticated ()">
如果用户通过身份验证,这是唯一将在DIV中呈现的代码。换句话说,如果用户未登录,则它不会显示在DIV标签之间的网页上。

<span sec: authentication = "name"> someone </ span>
如果用户使用其用户名登录,则会显示标签span之间的内容。在这种情况下,它显示了某人用户名。

有了这个,我们有一个安全的应用程序!是的,我们只使用两个Java类及其相应的HTML文件来保护网页。

源码: GitHub