[JAVA] Versuchen Sie es mit Spring Boot Security

Umgebung

Spring Boot 1.5.9.RELEASE Java 8 Maven 4.0.0

Überblick

Verwenden Sie Spring Security, um die Anmeldeinformationen in der Datenbank zu überprüfen und zu authentifizieren. DB verwendet H2DB und ORM verwendet Doma.

Einführung

Generieren Sie ein Projekt mit Spring Inirializr. spring-initializr.png

Da wir diesmal Doma für ORM verwenden, legen Sie die Annotationsverarbeitung fest. 注釈処理.png ファクトリー・パス.png

Code

Es werden nur diejenigen aufgelistet, die gegenüber der Standardeinstellung geändert wurden.

pom.xml(※Auszug)


	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<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>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.seasar.doma.boot/doma-spring-boot-starter -->
		<dependency>
			<groupId>org.seasar.doma.boot</groupId>
			<artifactId>doma-spring-boot-starter</artifactId>
			<version>1.1.1</version>
		</dependency>
	</dependencies>

UserEntity.java


package com.example.springbootsecuritysample.entity;

import java.util.Collection;

import org.seasar.doma.Entity;
import org.seasar.doma.Id;
import org.seasar.doma.jdbc.entity.NamingType;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import lombok.Getter;
import lombok.Setter;

/**
 *Entität in der USER-Tabelle
 * @author T.Harao
 *
 */
@Entity(naming = NamingType.SNAKE_UPPER_CASE)
@Getter
@Setter
public class UserEntity implements UserDetails {

	@Id
	private String userId;
	private String password;

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		return null;
	}
	@Override
	public String getUsername() {
		return userId;
	}
	/**
	 *Geben Sie das von UserDetailsService zu überprüfende Kennwort zurück
	 *Wenn Sie Lombok verwenden, wenn das Feld "Passwort" hat
	 *GetPassword mit @Getter()Wird nicht benötigt, da es generiert wird
	 */
	@Override
	public String getPassword() {
		return password;
	}
	@Override
	public boolean isAccountNonExpired() {
		return true;
	}
	@Override
	public boolean isAccountNonLocked() {
		return true;
	}
	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}
	@Override
	public boolean isEnabled() {
		return true;
	}

}

UserDao.java


package com.example.springbootsecuritysample.dao;

import org.seasar.doma.Dao;
import org.seasar.doma.Select;
import org.seasar.doma.boot.ConfigAutowireable;

import com.example.springbootsecuritysample.entity.UserEntity;

/**
 *DAO greift auf die USER-Tabelle zu
 * @author T.Harao
 *
 */
@Dao
@ConfigAutowireable
public interface UserDao {

	@Select
	public UserEntity selectByUserId(String userId);

}

AuthService.java


package com.example.springbootsecuritysample.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import com.example.springbootsecuritysample.dao.UserDao;
import com.example.springbootsecuritysample.entity.UserEntity;

/**
 *Dienst, der die Authentifizierung übernimmt
 * @author T.Harao
 *
 */
@Service
public class AuthService implements UserDetailsService {

	@Autowired
	private UserDao dao;

	/**
	 *Benutzer wird geladen
	 */
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

		if(username == null || "".equals(username)) {
			throw new UsernameNotFoundException("Benutzer-ID wurde nicht eingegeben");
		}

		UserEntity user = dao.selectByUserId(username);
		if(user == null) {
			throw new UsernameNotFoundException("Die Benutzer-ID ist ungültig.");
		}

		return user;
	}

}

IndexForm.java


package com.example.springbootsecuritysample.form;

import org.hibernate.validator.constraints.NotEmpty;

import lombok.Getter;
import lombok.Setter;

/**
 *Von IndexController verwendetes Formular
 * @author T.Harao
 *
 */
@Getter
@Setter
public class IndexForm {

	@NotEmpty
	private String userId;
	@NotEmpty
	private String password;

}

IndexController.java


package com.example.springbootsecuritysample.controller;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import com.example.springbootsecuritysample.form.IndexForm;

/**
 *Einloggen
 * @author T.Harao
 *
 */
@Controller
@RequestMapping({"/", "/index"})
public class IndexController {

	@ModelAttribute
	public IndexForm initForm(){
		return new IndexForm();
	}

	/**
	 *Erstanzeige
	 * @param mv
	 * @return
	 */
	@RequestMapping(value = {"/", "/index"}, method = RequestMethod.GET)
	public ModelAndView index(ModelAndView mv) {
		mv.setViewName("index/index");
		return mv;
	}

	/**
	 *Zum Zeitpunkt des Authentifizierungsfehlers
	 * @param mv
	 * @return
	 */
	@RequestMapping(value = {"/", "/index"}, method = RequestMethod.POST)
	public ModelAndView login(@ModelAttribute @Validated IndexForm form, BindingResult result, ModelAndView mv) {

		if(!result.hasErrors()) {
			mv.addObject("errorMessage", "Falsche Anmeldeinformationen");
		}

		mv.setViewName("index/index");
		return mv;
	}

}

MenuController.java


package com.example.springbootsecuritysample.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

/**
 *Speisekarte
 * @author T.Harao
 *
 */
@Controller
@RequestMapping("/menu")
public class MenuController {

	/**
	 *Erstanzeige
	 * @param mv
	 * @return
	 */
	@RequestMapping(value = {"/", "/index"}, method = RequestMethod.GET)
	public ModelAndView index(ModelAndView mv) {
		mv.setViewName("menu/index");
		return mv;
	}

}

FailureHandler.java


package com.example.springbootsecuritysample.config.handler;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

/**
 *Handler, wenn die Authentifizierung fehlschlägt
 * @author T.Harao
 *
 */
@Component
public class FailureHandler implements AuthenticationFailureHandler {

	/**
	 *Wenn die Authentifizierung fehlschlägt
	 */
	@Override
	public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException exception) throws IOException, ServletException {

		//「/Weiterleiten
		RequestDispatcher dispatch = request.getRequestDispatcher("/");
		dispatch.forward(request, response);

	}

}

SuccessHandler.java


package com.example.springbootsecuritysample.config.handler;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
/**
 *Handler bei erfolgreicher Authentifizierung
 * @author T.Harao
 *
 */
@Component
public class SuccessHandler implements AuthenticationSuccessHandler {

	/**
	 *Wenn die Authentifizierung erfolgreich ist
	 */
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {

		//「/menu/Weiterleiten an
		response.sendRedirect(request.getContextPath() + "/menu/");

	}

}

SecurityConfig.java


package com.example.springbootsecuritysample.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;

import com.example.springbootsecuritysample.config.handler.FailureHandler;
import com.example.springbootsecuritysample.config.handler.SuccessHandler;
import com.example.springbootsecuritysample.service.AuthService;

/**
 *Sicherheitseinstellungen
 * @author T.Harao
 *
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private AuthService service;

	@Autowired
	private FailureHandler failureHandler;

	@Autowired
	private SuccessHandler successHandler;

	/**
	 *Web-Sicherheitseinstellungen
	 */
	@Override
    public void configure(WebSecurity web) throws Exception {

		//Statische Ressourcen(images、css、javascript)Beim Zugriff auf die H2DB-Konsole werden die Sicherheitseinstellungen ignoriert
		web.ignoring().antMatchers("/css/**", "/fonts/**", "/images/**", "/js/**", "/h2-console/**");

	}

	/**
	 *HttpSecurity-Einstellungen
	 */
	@Override
	protected void configure(HttpSecurity http) throws Exception {

		//Autorisierungseinstellungen
		http.authorizeRequests()
			//Legen Sie eine URL fest, auf die ohne Authentifizierung zugegriffen werden kann
			.antMatchers("/", "/index/**").permitAll()
			//Für die Authentifizierung sind andere als die oben genannten Einstellungen erforderlich
			.anyRequest().authenticated();

		//Login-Einstellungen
		http.formLogin()
			//Legen Sie den Pfad für die Authentifizierungsverarbeitung fest
			.loginProcessingUrl("/index/login")
			//Legen Sie den Anmeldeformularpfad fest
			.loginPage("/")
			.loginPage("/index/**")
			//Stellen Sie die URL so ein, dass sie nach erfolgreicher Authentifizierung umgeleitet wird
			.defaultSuccessUrl("/menu/")
			//Legen Sie die URL fest, die weitergeleitet werden soll, wenn die Authentifizierung fehlschlägt
			.failureForwardUrl("/")
			//Legen Sie die URL fest, die bei erfolgreicher Authentifizierung weitergeleitet werden soll
			//.successForwardUrl("/")
			//Legen Sie die Handlerklasse fest, die aufgerufen werden soll, wenn die Authentifizierung erfolgreich ist
			//.successHandler(successHandler)
			//Legen Sie die URL fest, die umgeleitet werden soll, wenn die Authentifizierung fehlschlägt
			//.failureUrl("/menu/")
			//Legen Sie eine Handlerklasse fest, die aufgerufen werden soll, wenn die Authentifizierung fehlschlägt
			//.failureHandler(failureHandler)
			//Legen Sie den Namen des Benutzernamens und des Kennwortparameters fest
			.usernameParameter("userId").passwordParameter("password");

	}

	/**
	 *Aufbau
	 */
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {

		//Setzen Sie "NoOpPasswordEncoder", da das Passwort im Klartext in der Datenbank registriert ist.
		auth.userDetailsService(service)
			.passwordEncoder(NoOpPasswordEncoder.getInstance());

	}


}

layout.html


<!DOCTYPE html>
<html
	xmlns        = "http://www.w3.org/1999/xhtml"
	xmlns:th     = "http://www.thymeleaf.org"
	xmlns:layout = "http://www.ultraq.net.nz/thymeleaf/layout"
>
<head>
	<meta charset="UTF-8" />
	<title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">Frühlingssicherheitstest</title>
	<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css" th:href="@{/css/bootstrap.min.css}" media="all" />
	<link rel="stylesheet" type="text/css" href="/css/bootstrap-theme.min.css" th:href="@{/css/bootstrap-theme.min.css}" media="all" />

	<script type="text/javascript" src="/js/jquery-1.12.4.min.js" th:src="@{/js/jquery-1.12.4.min.js}"></script>
	<script type="text/javascript" src="/js/bootstrap.min.js" th:src="@{/js/bootstrap.min.js}"></script>
</head>
<body>
	<div class="contents" layout:fragment="contents"></div>
</body>
</html>

index/index.html


<!DOCTYPE html>
<html
	xmlns        = "http://www.w3.org/1999/xhtml"
	xmlns:th     = "http://www.thymeleaf.org"
	xmlns:layout = "http://www.ultraq.net.nz/thymeleaf/layout"
	layout:decorator="layout"
	>
<head>
	<title>Einloggen</title>
</head>
<body>
	<div layout:fragment="contents">
		<form class="form-horizontal" method="POST" action="/index/login/" th:action="@{/index/login}" th:object="${indexForm}">
			<div th:text="${errorMessage}?: ''" class="col-sm-offset-2 text-danger"></div>
			<div class="form-group">
				<p th:if="${#fields.hasErrors('*{userId}')}" th:errors="*{userId}" class="col-sm-offset-2 text-danger"></p>
				<label for="user-id" class="col-sm-2 control-label">Benutzeridentifikation</label>
				<div class="col-sm-5">
					<input type="text" class="form-control" id="user-id" th:field="*{userId}" placeholder="Benutzeridentifikation" />
				</div>
			</div>
			<div class="form-group">
				<p th:if="${#fields.hasErrors('*{password}')}" th:errors="*{password}" class="col-sm-offset-2 text-danger"></p>
				<label for="password" class="col-sm-2 control-label">Passwort</label>
				<div class="col-sm-5">
					<input type="password" class="form-control" id="password" th:field="*{password}" placeholder="Passwort" />
				</div>
			</div>
			<div class="form-group">
				<input type="submit" class="btn btn-primary col-sm-2 col-sm-offset-2" name="login" value="Einloggen" />
				<input type="reset" class="btn btn-default col-sm-2 col-sm-offset-1" name="clear" value="klar" />
			</div>
		</form>
	</div>
</body>
</html>

menu/index.html


<!DOCTYPE html>
<html
	xmlns        = "http://www.w3.org/1999/xhtml"
	xmlns:th     = "http://www.thymeleaf.org"
	xmlns:layout = "http://www.ultraq.net.nz/thymeleaf/layout"
	layout:decorator="layout"
	>
<head>
	<title>Speisekarte</title>
</head>
<body>
	<div layout:fragment="contents">
		<h2>Speisekarte</h2>
	</div>
</body>
</html>

application.yaml


#spring
spring:
  profiles:
    active: dev
  datasource:
    url: jdbc:h2:./db

#server
server:
  contextPath: /security-sample

#doma
doma:
  dialect: h2

application-dev.yaml


#spring
spring:
  h2:
    console:
      enabled: true
  thymeleaf:
    cache: false

application-production.yaml


#spring
spring:
  h2:
    console:
      enabled: false
  thymeleaf:
    cache: true

selectByUserId.sql


select
	user_id
	,password
from
	user
where
	user_id = /*userId*/''

schema.sql


--drop table if exists user;
create table if not exists user (
	user_id		varchar(30)	not null	primary key
	,password	varchar(30)	not null
);

data.sql


insert into user (user_id,password) values ('test','pass');

Die Ordnerstruktur ist wie folgt. パッケージエクスプローラー.PNG

Funktionsprüfung

Greifen Sie auf [http: // localhost: 8080 / security-sample /](http: // localhost: 8080 / security-sample /) zu und gehen Sie zu Geben Sie "test" als Benutzer-ID und "pass" als Passwort ein, um zum Menübildschirm zu gelangen. Anmeldebildschirm ログイン.PNG Menübildschirm メニュー.PNG

Verarbeitung nach der Authentifizierung

Die Verarbeitung, wenn die Authentifizierung erfolgreich ist oder fehlschlägt, wird im folgenden Teil von "SecurityConfig.java" beschrieben.

SecurityConfig.java


	/**
	 *HttpSecurity-Einstellungen
	 */
	@Override
	protected void configure(HttpSecurity http) throws Exception {

		//Autorisierungseinstellungen
		http.authorizeRequests()
			//Legen Sie eine URL fest, auf die ohne Authentifizierung zugegriffen werden kann
			.antMatchers("/", "/index/**").permitAll()
			//Für die Authentifizierung sind andere als die oben genannten Einstellungen erforderlich
			.anyRequest().authenticated();

		//Login-Einstellungen
		http.formLogin()
			//Legen Sie den Pfad für die Authentifizierungsverarbeitung fest
			.loginProcessingUrl("/index/login")
			//Legen Sie den Anmeldeformularpfad fest
			.loginPage("/")
			.loginPage("/index/**")
			//Stellen Sie die URL so ein, dass sie nach erfolgreicher Authentifizierung umgeleitet wird
			.defaultSuccessUrl("/menu/")
			//Legen Sie die URL fest, die weitergeleitet werden soll, wenn die Authentifizierung fehlschlägt
			.failureForwardUrl("/")
			//Legen Sie die URL fest, die bei erfolgreicher Authentifizierung weitergeleitet werden soll
			//.successForwardUrl("/")
			//Legen Sie die Handlerklasse fest, die aufgerufen werden soll, wenn die Authentifizierung erfolgreich ist
			//.successHandler(successHandler)
			//Legen Sie die URL fest, die umgeleitet werden soll, wenn die Authentifizierung fehlschlägt
			//.failureUrl("/menu/")
			//Legen Sie eine Handlerklasse fest, die aufgerufen werden soll, wenn die Authentifizierung fehlschlägt
			//.failureHandler(failureHandler)
			//Legen Sie den Namen des Benutzernamens und des Kennwortparameters fest
			.usernameParameter("userId").passwordParameter("password");

	}

Ich habe auskommentiert, aber wenn die Authentifizierung erfolgreich ist und fehlschlägt Sie können die Verarbeitung umleiten, weiterleiten und an die Handlerklasse delegieren.

Das diesmal erstellte Projekt befindet sich in hier

Recommended Posts

Versuchen Sie es mit Spring Boot Security
Spring Boot Tutorial Verwenden der Spring Security-Authentifizierung
Versuchen Sie es mit Spring Boot mit VS-Code
Versuchen Sie es mit Spring JDBC
Teil 1: Versuchen Sie, die von Spring Security 5 unterstützte OAuth 2.0-Anmeldung mit Spring Boot zu verwenden
Versuchen Sie die LDAP-Authentifizierung mit Spring Security (Spring Boot) + OpenLDAP
Versuchen Sie Spring Boot auf dem Mac
Versuchen Sie es mit einem DI-Container mit Laravel und Spring Boot
Versuchen Sie, mit Keycloak mit Spring Security SAML (Spring 5) zu arbeiten.
Versuchen Sie es mit Maven
Versuchen Sie es mit powermock-mockito2-2.0.2
Versuchen Sie es mit GraalVM
Versuchen Sie es mit jmockit 1.48
Versuchen Sie die Verschlüsselung / Entschlüsselung von Spring Security AES256-Zeichenfolgen
Fordern Sie Spring Boot heraus
Der Spring Boot @ WebMvcTest-Test aktiviert die Standardsicherheit von Spring Security
Versuchen Sie Spring Boot 1 (Umgebungskonstruktion ~ Tomcat-Start)
Spring Boot Form
Asynchrone Verarbeitung mit Spring Boot unter Verwendung von @Async
Spring Boot Denken Sie daran
gae + frühlingsstiefel
Erreichen Sie die BASIC-Authentifizierung mit Spring Boot + Spring Security
Hash-Passwörter mit Spring Boot + Spring Security (mit Salt, mit Stretching)
[FCM] Implementierung der Nachrichtenübertragung mit FCM + Spring Boot
Erstellen Sie eine Spring Boot-Anwendung mit IntelliJ IDEA
Versuchen Sie, die Anmeldefunktion mit Spring Boot zu implementieren
Versuchen Sie, die Migration mit Spring Boot Flyway zu automatisieren
Wenden Sie Twitter Bootstrap 4 mithilfe von Webjars auf Spring Boot 2 an
[Einführung in Spring Boot] Authentifizierungsfunktion mit Spring Security
Erstellen Sie mit Spring Boot 2.0 einen Spring Cloud Config Server mit Sicherheit
Versuchen Sie es mit dem Axon Framework
SPRING BOOT Lernaufzeichnung 01
Frühlingsstiefel + Heroku Postgres
Versuchen Sie es mit der REST-API von JobScheduler
Informationen zur Spring Security-Authentifizierung
Versuchen Sie es mit der Methode java.lang.Math
Versuchen Sie es mit der WhiteBox von PowerMock
Schreiben von Frühlingsstiefel-Memos (1)
Erster Frühlingsstiefel (DI)
SPRING BOOT Lernprotokoll 02
Spring Boot2 Spickzettel
Spring Boot-Ausnahmebehandlung
Spring Boot Servlet-Zuordnung
Spring Boot Entwicklung-Entwicklungsumgebung-
Spring Boot-Lernverfahren
Spring Boot lernen [Anfang]
Schreiben von Spring Boot-Memos (2)
Spring Boot 2.2 Dokumentzusammenfassung
[Spring Boot] DataSourceProperties $ DataSourceBeanCreationException
Versuchen Sie es mit Talend Teil 1
Spring Boot 2.3 Verfügbarkeit von Anwendungen
Spring Boot Tutorials Themen
Versuchen Sie es mit der F # -Liste
Versuchen Sie es mit der Methode each_with_index
Mit Spring Boot herunterladen
Testen von JPA-Entitäten und -Repositorys mit Spring Boot @DataJpaTest
[Hinweis] Festlegen der Datei bei Verwendung von Logback mit Spring Boot
Verwendungshinweis zu Spring Security: Zusammenarbeit mit Spring MVC und Boot