*** Addition: The description in home.html and the screenshot image were incorrect, so I corrected it. *** ***
I wanted to create a login / logout function using Spring Security, but I was addicted to various things and got stuck for about 2 days. Finally, I decided to make it according to the official Spring guide. →https://spring.io/guides/gs/securing-web/
Since the whole sentence is in English, I managed to understand it while writing while looking up the meaning, so I will share it for beginners.
New → Spring Starter Project Select and create with the following items.
This is absolutely! That's not to say, but I think that the movement will change depending on the environment, so I think that it is better for people who want to copy and paste for the time being.
Now, let's modify the created project.
First, add the description "I'll use Spring Security!" To pom.xml. (Spring officially does it after creating the Hello World application, but this time I will do it first) What is pom.xml? If so, please try google. Roughly speaking, pom.xml is like a Maven config file. (Excuse me if I am wrong)
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>login-Training-SpringBoot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>login-Training-SpringBoot</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
//Add here!
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Between <dependencies> </ dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
To add. With this, the setting "I will use Spring Security!" Is completed.
First of all, we will create an application that Hello World without security.
Because it uses Thymeleaf template
src/main/resources/templates/home.html
Create an HTML file under the templates folder as shown below.
home.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-springsecurity3">
<head>
<meta charset="UTF-8">
<title>Hello,SpringSecurity!</title>
</head>
<body>
<h1>WELCOME!</h1>
<br>
<p>Login<a th:href="@{/hello}">Here</a></p>
<p><a th:href="@{/}">New user registration</a></p>
</body>
</html>
First about namespaces. A namespace is a "namespace" created so that a computer can identify a combination of multiple vocabularies on XML where the markup language can be freely designed. (literally) It's too conceptual and hard to understand, This article is easy to understand about namespaces. A brief description of the XML namespace
The "xmlns" used this time is called "XML namespace", and it seems that the computer can be identified by combining the vocabulary type and URI.
Also,
In many cases, the http: scheme is used for the URI that indicates the namespace, so I get the impression that something can be retrieved, but this is primarily the role of "ID" as the name implies. Please understand that it will be fulfilled
Well, I'm sure you think it's a tag identification ID here.
Here we set the default namespace with xmlns =" "
and Setting th: with
xmlns: th =" ", The sec: is set with
xmlns: sec =" "`.
Next is the link to "/ hello" Here, the link is posted in Thymeleaf notation. The @ {...} part of the th: href attribute is the link destination. In this case, it means that it is linked to "localhost: 8080 / hello". (Although the link for new user registration is also described, it is not implemented this time because it is only displayed and not implemented)
How to write Thymeleaf Reference: Completely master Thymeleaf with the minimum required sample
[hello.html] Now, create hello.html that describes the link earlier.
hello.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<meta charset="UTF-8">
<title>Hello,SpringSecurity!</title>
</head>
<body>
<h3>Welcome!</h3>
</body>
</html>
Welcome here once! Just display.
Next, create a class to set MVC.
src/main/java/hello/MvcConfig.java
Place in.
MvcConfig.java
package hello;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
registry.addViewController("/").setViewName("home");
registry.addViewController("/hello").setViewName("hello");
registry.addViewController("/login").setViewName("login");
}
}
About implements: Implement the interface! How to use implements in Java [For beginners]
Roughly speaking interface (specification)-> implemented class (insert the actual definition into the specification)-> use that method It is an image like that.
Create a configuration class that inherits from the WebSecurityConfigurerAdapter class.
src/main/java/hello/WebSecurityConfig.java
Arranged like this.
WebSecurityConfig.java
package hello;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception{
http
.authorizeRequests()
// "/"When/home is accessible to all users
.antMatchers("/","/home").permitAll()
//Authentication is required for access to other than the above
.anyRequest().authenticated()
.and()
//Login and logout URL specifications and permissions for all users
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Bean
@Override
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("user")
.password("pass")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
First of all, inheritance should be inherited when creating a class.
So, @EnableWebSecurity, but it seems that you can use the WebSecurity function by writing this. Well, it's a security feature on the Web! That is the description. I'll leave the exact definition to Google Sensei. ..
As for the URL path and access rights, as described in the comment. Allow access to all users with permitAll () Requires authentication with authenticated () I feel like.
Finally, the userDetailsService () part, First, @Bean is the same as JavaBeans, You can generate a user's bean (concrete contents) by using @Bean annotation. It also overrides the UserDetailsService class, where you specify the username and password. Here, username is username, password is pass, and role is USER.
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<meta charset="UTF-8">
<title>LoginPage</title>
</head>
<body>
<div th:if="${param.error}">
The user name or password is incorrect
</div>
<div th:if="${param.logout}">
Logped out
</div>
<form th:action="@{/login}" method="post">
<div><label>username:<input type="text" name="username" /></label></div>
<div><label>password:<input type="password" name="password" /></label></div>
<div><input type="submit" value="Login" /></div>
</form>
</body>
</html>
src/main/resources/templates/login.html
Created in.
$ {param} is an unfamiliar object called an "implicit object".
To explain it roughly, it gets the parameters after the. (Dot). (Search for "$ {param} EL expression")
So you can get the parameter of error with $ {param.error}
.
In this case, if error is true, an error message is displayed, and if logout is true, a message to that effect is displayed.
Also, according to the Spring official, it seems that if login fails, it redirects to " / login? Error "
.
If the user fails to authenticate, the page is redirected to "/login?error" and our page displays the appropriate error message.
By the way, it seems that it is necessary to add / at the end of the input tag when writing XML. Why an error occurs if you do not add a slash to the input tag in Spring Boot 2
hello.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<meta charset="UTF-8">
<title>Hello,SpringSecurity!</title>
</head>
<body>
<h2>Hello!</h2>
<h1 th:inline="text">Hello[[${#httpServletRequest.remoteUser}]]!</h1>
<form th:action="@{/logout}" method="post">
<input type="submit" value="Log out" />
</form>
<p></p>
</body>
</html>
The display part of the body has been rewritten.
[[$ {# httpServletRequest.remoteUser}]]
Get the user name in the part of [[$ {# httpServletRequest.remoteUser}]]
and display it on the screen.
We display the username by using Spring Security’s integration with HttpServletRequest#getRemoteUser(). (From the official guide)
Here, we will get the username using the getRemoteUser () method of HttpServletRequest! Is written. Using this idea, Get remoteUser data with httpServletRequest It is an image like that. The double brackets [[]] seem to be for data conversion as far as I can see. I think it's because I take two steps: get it → format it for output. Perhaps.
I'm finally here! All you have to do now is set up your project to run.
Officially, a new execution class Application.java is created in the hello package, but while thinking that it is already in the com.example.demo package by default ... When I read it, it said something like "What should I do if it's in the hello package?", So I created it just in case. (It may not make sense because I haven't translated it properly)
@ComponentScan tells Spring to look for other components, configurations, and services in the hello package, allowing it to find the controllers.
src/main/java/hello/Application.java
I will make it.
Application.java
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<meta charset="UTF-8">
<title>Hello,SpringSecurity!</title>
</head>
<body>
<h2>Hello!</h2>
<h1 th:inline="text">Hello[[${#httpServletRequest.remoteUser}]]!</h1>
<form th:action="@{/logout}" method="post">
<input type="submit" value="Log out" />
</form>
<p></p>
</body>
</html>
I think it's okay to delete the default execution class. I'm scared so I commented out the full text w
Finally completed! Let's run it now.
You can start it by right-clicking the project → Run → Spring Boot application.
After that, try accessing by typing http: // localhost: 8080
in the URL input field of your browser.
home.html
First, the home screen was output. You can see the link to the login page. I haven't used it yet, but new user registration is also displayed.
Press Log Out.
login.html
You have transitioned to the login screen. Since the user information is "Logged out", it is displayed as "Logged out".
Next, let's log in by entering the user name (user) and password (pass) that you specified.
hello.html
I was able to log in! Since the user name is "user", it is a little difficult to understand, but it is in the form of "Hello + user +!".
Now, let's enter the wrong user name or password.
login.html
The error is displayed properly.
Hmm, it was so long. If this can be done after understanding the mechanism, the application will be effective.
Thank you for your hard work!
Recommended Posts