Securing Your Website With Spring Boot
Want to learn more about securing your website with Spring Boot? Check out this post about securing your webpage with just two Java classes and their HTML files.
Join the DZone community and get the full member experience.
Join For FreeIn this post, I will explain how Spring manages security. I won't be covering everything, of course — the issue of security would be a big book, but we will at least take a look at how to secure a website.
As always, I want to start by saying that the source code can be found on my GitHub page. The program is made in Java using Spring Boot.
Well, let's start by look at how to secure a website in Spring.
Spring Boot is actually very simple because we will use what Spring calls starters, which are nothing but groups of packages grouped by the functions that they offer. So in this case, the package will include Web, Thymeleaf, and, of course, Security.
Here's a glimpse of Eclipse selecting the required packages.
As many of you already know, pom.xml file dependencies allow you to see more detail.
Thymeleaf is software that seamlessly integrates with Spring and creates webpage templates. This is similar to JSP, but Thymeleaf is a more improved version. Or, if you prefer JavaServer Faces, it would look more like JavaEE. The case is that it allows HTML pages to integrate seamlessly with our classes developed in Spring.
Since we want to see on our website, the username that we have recorded lets us use the library security Thymeleaf for Spring. To do this, we will include the following lines in our pom.xml file.
<GroupId> org.thymeleaf.extras <groupId/>
<ArtifactId> thymeleaf-extras-springsecurity4 <artifactId/>
<Version> 3.0.3.RELEASE <version/>
<Dependency/>
And here, you can see how it will structure our program
Now, we begin declaring our first class, which I have called the 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 ();
}
}
The first is to use labels @SpringBootApplication
and @EnableWebSecurity
. The first tag is obvious — since our application, we want to work with Spring Boot. The second is to specify that the web security is activated; honestly, this label is not required. Spring Boot is very clever, as we have seen package security (in the pom.xml, remember) in our project. It includes this message again, which is not necessarily a bad thing, as it provides further clarity but is, albeit, redundant.
Now, we specify that our class will inherit from theWebSecurityConfigurerAdapter
because we will overwrite some of the functions of that class. So, you need to understand Spring and look to see if there is a class that implements the interfaceWebSecurityConfigurer
, which implements the class WebSecurityConfigurerAdapter
, and if so, it uses the functions of that interface to configure the security application.
If we had a class that implements this interface, Spring simply would not access any page of our application, which, as you can probably understand, is not very practical.
Now, we need to write the function authenticationManagerBean
to return the class responsible to manage authentications (as its name suggests). Okay, you might be wondering: but what about if you only call the function to define? This is actually very simple because we use the @Bean
label for Spring. It is important to know where to get (injecting) the object type AuthenticationManager
because you need to control security.
In the function userDetailsService
, we define users who will have access to our website. In this case, we create two users: user and admin (yes, I know that I have not tried too hard choosing the names), each with its own password and role. Clarify that the ROLE is a free literal, meaning that this can be whatever you want. For example, USER_WITH_EYES — the fact is that then we will use that role, it must match letter by letter with the set.
Also, note that the password is encrypted, in this case, with the algorithm Bcrypt. We do this by calling the function passwordEncoder
, which is annotated with the Spring@Bean
label.
That is, Spring needs to know which encryption system we are using to store passwords, and it seeks an object that implements the interface PasswordEncoder
. If we fail, we cannot find the application.
I want to clarify that we are using the simplest way to declare users and store them, in memory, with the class InMemoryUserDetailsManager
. In a real program, it would use JdbcUserDetailsManager
, which would allow us to store them in a database. Or, this could include any other class that implements the interface UserDetailsManager
, as it could be LdapUserDetailsManager
if we use an LDAP service.
And since we need to define which parts of our application will be protected, the roles must have permission to access every part of it. Yes, I have written roles and nonusers, because as we have said before, when you define a user, you must assign a role. And normally, the filtering rules are applied by the group to which the user belongs. To set permissions for each resource, we will configure the object HttpSecurity received in the function protected void configure (HttpSecurity http).
I'll explain line by line what is done in this function:
-
csrf (). disable ()
First, we are looking at CSRF disable control. CRSF stands for Cross-site request forgery, as Wikipedia explains:
Cross-site request forgery, also known as one-click attack or session riding and abbreviated as CSRF (sometimes pronounced sea-surf) or XSRF, is a type of malicious exploit of a website where unauthorized commands are transmitted from a user that the web application trusts. There are many ways in which a malicious website can transmit such commands; specially-crafted image tags, hidden forms, and JavaScript XMLHttpRequests, for example, can all work without the user's interaction or even knowledge. Unlike cross-site scripting (XSS), which exploits the trust a user has for a particular site, CSRF exploits the trust that a site has in a user's browser.
Disabling the CRSF has the side effects that can perform a log out of a session with a request HTTP GET type, then default can only be done with a POST request:
-
.authorizeRequests () .antMatchers ( "/" "/ index", "/ webpublico"). permitAll ()
We specify that the petitions on this route with any of the strings "/", "/ index", "/ webpublico" will not have security. That is be permitted for everyone.
-
antMatchers ( "/webprivado"). authenticated ()
We specify that requests to the path "/webprivado" can only be processed if the user is authenticated, without specifying what role should belong.
-
.antMatchers ( "/webadmin"). hasRole ( "ADMIN")
Only users who are part of the group ADMIN will have access to the URL "/webadmin."
The function antMatchers
allows the use of regular expressions, so if, for example, we would like to apply a rule to all that depends on a route, we could put this:
http.antMatchers ( "/ users /**"). hasRole ( "USER") to specify that any request to the URL /users /XXX only has access to users belonging to the group USER.
-
.formLogin(). loginPage( "/login"). permitAll()
We specify that the login page will be "/login" and allowed to reach everyone.
-
logout(). permitAll()
We specify the logout page should be allowed to reach everyone. By default, this page answers in the URL "/logout."
Perfect. We have defined the security of our websites. Now, we just define the entry points to the pages. This is done in the class 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";
}
}
As seen above, a class has many mysteries. W simply specify the label @Controller
to be a class where we can define entry points for web requests.
We have different functions in the label @RequestMapping
to specify the URL and be processed by each function. Thus, the function start will be called when a request to the URL, "/" or "/index." Note that we need to put in the initial bar.
The string returned will be the template that Thymeleaf returned so that the call start function will return the "index.html" template, as shown below:
<! 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>
How does it look like pure HTML? This is one of the advantages of using Thymeleaf standard HTML tags. I will not explain the language here, but I will explain some of the labels used:
<a th:href="@{/webpublico}"> — Create a link to the URL "/webpublico." It would be like using the "tag <A href="/webpublico">.
<div sec: Authorize = "isAuthenticated ()"> — This is the only code that will be rendered in the DIV if the user is authenticated. In other words, if the user is not logged in, it is not displayed on the web page that is between DIV tags (in fact, it will not show on the webpage or the DIV).
<span sec: authentication = "name"> someone </ span> — If the user is logged in with their username, it will show what you have between tags span. In this case, it shows someone.
And with this, we have a secure application! Yep, we secure out a webpage with only two Java classes and their corresponding HTML files.
To finish this post, I leave some screenshots of the application:
This is the public page.
This looks at the home page once it has identified the 'user.'
Now, we are identifying the user "user:"
Hope this helps! Happy coding.
Opinions expressed by DZone contributors are their own.
Comments