在这篇文章中,我将解释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