在这篇文章中,我将解释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 <b>public</b> <b>class</b> WebSecurityConfiguration <b>extends</b> WebSecurityConfigurerAdapter { <b>public</b> <b>static</b> <b>void</b> main (String [] args) { SpringApplication.run (WebSecurityConfiguration.<b>class</b>, args); } @Bean @Override <b>public</b> AuthenticationManager authenticationManagerBean() throws Exception { <b>super</b>.authenticationManagerBean <b>return</b>(); } @Bean @Override <b>public</b> UserDetailsService userDetailsService() { UserDetails user = User.builder()(). Username(<font>"user"</font><font>).Password(passwordEncoder().Encode( </font><font>"secret"</font><font>)).roles ( </font><font>"USER"</font><font>) build().; UserDetails UserAdmin = User.builder(). Username(</font><font>"admin"</font><font>).Password(passwordEncoder().Encode( </font><font>"secret"</font><font>)).roles ( </font><font>"ADMIN"</font><font>) build().; <b>return</b> <b>new</b> InMemoryUserDetailsManager (user, UserAdmin); } @Bean <b>public</b> PasswordEncoder passwordEncoder() { <b>return</b> <b>new</b> BCryptPasswordEncoder(); } @Override <b>protected</b> <b>void</b> set (http HttpSecurity) throws Exception { http .csrf().disable() .authorizeRequests() .antMatchers( </font><font>"/"</font><font> </font><font>"/ index"</font><font>, </font><font>"/ webpublico"</font><font>). permitAll() .antMatchers( </font><font>"/ webprivado"</font><font>). authenticated() .antMatchers( </font><font>"/ webadmin"</font><font>). hasRole ( </font><font>"ADMIN"</font><font>). and() .formLogin() .loginPage( </font><font>"/ login"</font><font>) .permitAll() .and() .logout() </font><font><i>// get method for I desabilitado CSRF</i></font><font> .permitAll(); } } </font>
标注@SpringBootApplication 和 @EnableWebSecurity。第一个希望使用Spring Boot必注;第二个是指定激活Web安全性; 老实说,这个标签不是必需的,Spring Boot非常聪明,因为我们已经看到了项目中引入了安全性包(在pom.xml中)。但它提供了进一步的清晰度,但是,尽管是多余的。
@SpringBootApplication @EnableWebSecurity <b>public</b> <b>class</b> WebSecurityConfiguration <b>extends</b> WebSecurityConfigurerAdapter {
现在,我们指定我们的类将继承自WebSecurityConfigurerAdapter,因为我们会覆盖该类的一些功能。因此,你需要了解Spring并查看是否存在类实现接口WebSecurityConfigurer,后者又实现接口WebSecurityConfigurerAdapter,如果有,则使用该接口的功能来配置安全应用程序。
如果我们有一个实现此接口的类,Spring就不会访问我们应用程序的任何页面,但不是很实用。
@Bean @Override <b>public</b> AuthenticationManager authenticationManagerBean() throws Exception { <b>super</b>.authenticationManagerBean <b>return</b>(); }
现在,我们需要编写一个函数 authenticationManagerBean 来返回负责管理身份验证的类(顾名思义)。重要的是要知道在哪里获取(注入)对象类型AuthenticationManager, 因为只有通过它你才能控制Spring的安全性。
@Bean @Override <b>public</b> UserDetailsService userDetailsService() { UserDetails user = User.builder()(). Username(<font>"user"</font><font>).Password(passwordEncoder().Encode( </font><font>"secret"</font><font>)).roles ( </font><font>"USER"</font><font>) build().; UserDetails UserAdmin = User.builder(). Username(</font><font>"admin"</font><font>).Password(passwordEncoder().Encode( </font><font>"secret"</font><font>)).roles ( </font><font>"ADMIN"</font><font>) build().; <b>return</b> <b>new</b> InMemoryUserDetailsManager (user, UserAdmin); } </font>
在userDetailsService,我们定义可以访问我们网站的用户。在这种情况下,我们创建了两个用户:user和admin,每个用户都有自己的密码和角色。角色名称USER和ADMIN可以自己定义,可以是你想要的任何字母。例如,USER_WITH_EYES - 事实是我们一旦使用该角色名,它必须与你定义的角色集合的角色名称逐个字母匹配。
另请注意,在这种情况下,密码是使用算法Bcrypt加密的。我们通过调用函数来完成此操作,该函数 passwordEncoder使用Spring @Bean 标签进行注释。
也就是说,Spring需要知道我们用来存储密码的加密系统,并且它寻找实现接口的对象 PasswordEncoder:
@Bean <b>public</b> PasswordEncoder passwordEncoder() { <b>return</b> <b>new</b> BCryptPasswordEncoder(); }
我想澄清一下,我们使用最简单的方法来声明用户并将其存储在内存中 InMemoryUserDetailsManager。在真实的程序中,它会使用JdbcUserDetailsManager,存储在数据库中。或者可能是包括实现接口UserDetailsManager的任何其他类, 如果我们使用LDAP服务可能会是LdapUserDetailsManager。
@Override <b>protected</b> <b>void</b> set (http HttpSecurity) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers( <font>"/"</font><font> </font><font>"/ index"</font><font>, </font><font>"/ webpublico"</font><font>). permitAll() .antMatchers( </font><font>"/ webprivado"</font><font>). authenticated() .antMatchers( </font><font>"/ webadmin"</font><font>). hasRole ( </font><font>"ADMIN"</font><font>). and() .formLogin() .loginPage( </font><font>"/ login"</font><font>) .permitAll() .and() .logout() </font><font><i>// get method for I desabilitado CSRF</i></font><font> .permitAll(); } </font>
由于我们需要定义应用程序的哪些部分将受到保护,因此角色必须具有访问其每个部分的权限。是的,是角色而非用户,因为正如我们之前所说,当您定义用户时,您必须分配一个角色。通常,过滤规则是适用于用户所属的组,要为每个资源设置权限,我们要在函数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 <b>public</b> <b>class</b> WebController { @RequestMapping ({ <font>"/"</font><font>, </font><font>"index"</font><font>}) <b>public</b> String start () { <b>return</b> </font><font>"index"</font><font>; } @RequestMapping ( </font><font>"/webprivado"</font><font>) <b>public</b> <b>private</b> String () { </font><font>"Private"</font><font> <b>return</b>; } @RequestMapping ( </font><font>"/webpublico"</font><font>) <b>public</b> String loginpub () { </font><font>"Public"</font><font> <b>return</b>; } @RequestMapping ( </font><font>"/webadmin"</font><font>) <b>public</b> String admin () { <b>return</b> </font><font>"admin"</font><font>; } @RequestMapping ( </font><font>"/login"</font><font>) <b>public</b> String login () { <b>return</b> </font><font>"login"</font><font>; } } </font>
如上所述,@Controller定义Web请求的入口点。
@RequestMapping来指定URL并由每个函数处理。因此,当对URL,“ / ”或“ /index ” 的请求时,将调用函数start。
返回的字符串将是Thymeleaf返回的模板,start函数将返回“index.html”模板,如下所示:
<! DOCTYPE html> <Html xmlns = <font>"http://www.w3.org/1999/xhtml"</font><font> xmlns: th = </font><font>"http://www.thymeleaf.org"</font><font> xmlns: sec = </font><font>"http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"</font><font>> <Head> <Title> Home Page </ title> </ Head> <Body> <H1> Home Page </ h1> <P> <a th:href=</font><font>"@{/webpublico}"</font><font>> Click here to view a page </a> <b>public</b>. </ P> <P> If you are a regular user clicks </a> <a th:href=</font><font>"@{/webprivado}"</font><font>> here to view a <b>private</b> page </ p> <P> If you are a regular administrator </a> click <a th:href=</font><font>"@{/webadmin}"</font><font>> here to see the profile Administrator </ p> <Div sec: Authorize = </font><font>"isAuthenticated ()"</font><font>> Hello <span sec: authentication = </font><font>"name"</font><font>> someone </ span> <P> <a th:href=</font><font>"@{/logout}"</font><font>> Disconnect </a> </ p> </ Div> </ Body> </ Html> </font>
它看起来像纯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