> Java > java지도 시간 > 본문

Spring Boot 및 Thymeleaf를 사용한 양식 로그인

WBOY
풀어 주다: 2024-07-25 19:39:43
원래의
361명이 탐색했습니다.

양식 기반 로그인은 Spring Boot 애플리케이션의 웹 프런트엔드를 보호하기 위한 첫 번째 선택인 경우가 많습니다. 이는 사용자가 사용자 이름과 비밀번호로 자신을 인증한 후에만 애플리케이션의 특정 영역에 액세스할 수 있도록 하며 이 상태는 세션에 저장됩니다. Spring Boot 애플리케이션에 양식 기반 로그인을 추가하는 데 필요한 단계는 무엇입니까?

간단한 애플리케이션으로 시작하세요

먼저 현재 버전 3.3.2에서 Bootify Builder를 사용하여 간단한 Spring Boot 애플리케이션을 만듭니다. 이를 위해 프로젝트 열기를 클릭하기만 하면 됩니다. 여기서는 Thymeleaf + Bootstrap을 프런트엔드 스택으로 선택합니다. Thymeleaf는 Spring Boot에서 가장 많이 사용되는 템플릿 엔진이며 서버 측 렌더링을 허용합니다. Bootstrap은 WebJar로 앱에 통합됩니다. 연결하려는 데이터베이스를 선택하세요. 지금은 내장된 데이터베이스도 연결됩니다.

엔티티 탭에서 User 테이블과 TodoList 테이블을 생성하고 N:1 관계로 연결합니다. TodoList의 경우 프런트엔드에 대한 CRUD 옵션을 활성화합니다 - 이는 나중에 Spring Security로 보호되는 영역이 됩니다.

Form Login with Spring Boot and Thymeleaf
  매우 간단한 데이터베이스 스키마 미리보기

이제 완성된 애플리케이션을 다운로드하여 즐겨 사용하는 IDE로 가져올 수 있습니다.

Form Login with Spring Boot and Thymeleaf
  IntelliJ 애플리케이션의 첫 번째 버전

스프링 시큐리티 구성

Spring Security의 도움으로 양식 기반 로그인이 제공됩니다. 따라서 먼저 build.gradle 또는 pom.xml에 각각 추가할 관련 종속성이 필요합니다.

implementation('org.springframework.boot:spring-boot-starter-security')
implementation('org.thymeleaf.extras:thymeleaf-extras-springsecurity6')
로그인 후 복사

spring-boot-starter-security 모듈은 Spring Security를 ​​통합합니다. thymeleaf-extras-springsecurity6에는 Thymeleaf 템플릿에 인증 상태를 제공하는 작은 도우미가 포함되어 있습니다. 이에 대해서는 나중에 자세히 설명하겠습니다.

이를 통해 우리는 이미 중앙 보안 구성을 제공할 수 있습니다. 최종 버전에서 직접

@Configuration
@EnableMethodSecurity(prePostEnabled = true)
public class HttpSecurityConfig {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    @Bean
    public AuthenticationManager authenticationManager(
            final AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    public SecurityFilterChain configure(final HttpSecurity http) throws Exception {
        return http.cors(withDefaults())
                .csrf(withDefaults())
                .authorizeHttpRequests(authorize -> authorize.anyRequest().permitAll())
                .formLogin(form -> form
                    .loginPage("/login")
                    .usernameParameter("email")
                    .failureUrl("/login?loginError=true"))
                .logout(logout -> logout
                    .logoutSuccessUrl("/login?logoutSuccess=true")
                    .deleteCookies("JSESSIONID"))
                .exceptionHandling(exception -> exception
                    .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login?loginRequired=true")))
                .build();
    }

}
로그인 후 복사

  양식 로그인 구성

이론적으로 Spring Security는 더 적은 구성으로 로그인 양식을 제공할 수 있지만, 이는 사용자에게 표시하려는 디자인과 일부 메시지가 부족합니다. 하지만 먼저 구성을 살펴보겠습니다.

BCryptPasswordEncoder는 요즘 비밀번호의 해시를 개별 솔트와 함께 단일 필드에 저장하는 표준입니다. 레거시 요구 사항이 없으면 이 요구 사항을 사용해야 합니다. 또한 다른 서비스에 통합할 수 있도록 AuthenticationManager를 빈으로 제공합니다.

Spring 3.0부터 필수 접근 방식인 SecurityFilterChain을 세 번째 빈으로 생성합니다. 해당 공격 벡터를 차단하려면 CORS와 CSRF를 모두 적절하게 구성해야 합니다. 일반적으로 기본 구성으로 충분합니다.

구성 클래스에 @EnableMethodSecurity 주석을 배치했으며 나중에 @PreAuthorize(...)를 사용하여 원하는 컨트롤러 엔드포인트를 보호합니다. 따라서 permitAll()을 사용하여 전체 애플리케이션에 대한 액세스를 허용합니다. 주석 기반 보안이 없으면 이곳에서도 보호되는 리소스에 대한 경로를 구성해야 합니다.

formLogin() 및 logout() 메소드는 항상 사용자에게 적절한 메시지를 표시할 수 있도록 후속 컨트롤러에 맞게 맞춤설정되었습니다. Spring Security는 POST 요청을 통해 사용자 이름과 비밀번호를 제출할 수 있는 로그인용 엔드포인트를 자동으로 제공합니다. 여기서는 사용자 이름 필드의 이름을 "email"로 변경합니다. 로그아웃은 이후 매개변수를 통해 로그인 페이지로 다시 리디렉션되도록 수정됩니다.

데이터베이스에서 사용자 로드 중

이미 생성된 테이블에서 사용자를 로드하려면 UserDetailsService 구현을 빈으로 제공해야 합니다. 자동으로 찾아서 사용자 소스로 사용합니다.

@Service
public class HttpUserDetailsService implements UserDetailsService {

    private final UserRepository userRepository;

    public HttpUserDetailsService(final UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public HttpUserDetails loadUserByUsername(final String username) {
        final User user = userRepository.findByEmailIgnoreCase(username);
        if (user == null) {
            log.warn("user not found: {}", username);
            throw new UsernameNotFoundException("User " + username + " not found");
        }
        final List<SimpleGrantedAuthority> roles = Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
        return new HttpUserDetails(user.getId(), username, user.getHash(), roles);
    }

}
로그인 후 복사

  자동으로 사용자 소스로 사용되는 UserDetailsService 구현

우리 저장소에는 데이터베이스에 대해 검색 쿼리를 실행하기 위해 User findByEmailIgnoreCase(String email) 메소드를 추가해야 합니다. 대소문자를 무시하면 사용자가 이메일을 작성할 때 작은 실수를 할 수 있습니다. 여기서 역할은 항상 각 사용자에 대한 ROLE_USER입니다. 현재로서는 사용할 수 있는 등록 엔드포인트가 없으므로 지금은 애플리케이션과 함께 간단한 데이터 로더를 추가할 수 있습니다. 활성화하려면 "로컬" 프로필이 필요합니다.

@Component
@Profile("local")
public class UserLoader implements ApplicationRunner {

    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    public UserLoader(final UserRepository userRepository,
                      final PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    public void run(final ApplicationArguments args) {
        if (userRepository.count() != 0) {
            return;
        }
        final User user = new User();
        user.setEmail("test@test.com");
        user.setHash(passwordEncoder.encode("testtest"));
        userRepository.save(user);
    }

}
로그인 후 복사

  첫 번째 사용자를 로컬에서 초기화하는 도우미 클래스

Add login controller

With this we can already add the LoginController. Since the POST endpoint is automatically provided by Spring Security, a GET endpoint is sufficient here to show the template to the user.

@Controller
public class AuthenticationController {

    @GetMapping("/login")
    public String login(@RequestParam(name = "loginRequired", required = false) final Boolean loginRequired,
            @RequestParam(name = "loginError", required = false) final Boolean loginError,
            @RequestParam(name = "logoutSuccess", required = false) final Boolean logoutSuccess,
            final Model model) {
        model.addAttribute("authentication", new AuthenticationRequest());
        if (loginRequired == Boolean.TRUE) {
            model.addAttribute(WebUtils.MSG_INFO, WebUtils.getMessage("authentication.login.required"));
        }
        if (loginError == Boolean.TRUE) {
            model.addAttribute(WebUtils.MSG_ERROR, WebUtils.getMessage("authentication.login.error"));
        }
        if (logoutSuccess == Boolean.TRUE) {
            model.addAttribute(WebUtils.MSG_INFO, WebUtils.getMessage("authentication.logout.success"));
        }
        return "authentication/login";
    }

}
로그인 후 복사

  Backend for rendering the login page

The request parameters that we had already specified in our security configuration are converted to corresponding messages here. In our simple application from Bootify the corresponding helpers are already included. Here we also need the AuthenticationRequest object with getters and setters.

public class AuthenticationRequest {

    @NotNull
    @Size(max = 255)
    private String email;

    @NotNull
    @Size(max = 255)
    private String password;

}
로그인 후 복사

The corresponding template for our controller could then look like this.

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
        layout:decorate="~{layout}">
    <head>
        <title>[[#{authentication.login.headline}]]</title>
    </head>
    <body>
        <div layout:fragment="content">
            <h1 class="mb-4">[[#{authentication.login.headline}]]</h1>
            <div th:replace="~{fragments/forms::globalErrors('authentication')}" />
            <form th:action="${requestUri}" method="post">
                <div th:replace="~{fragments/forms::inputRow(object='authentication', field='email')}" />
                <div th:replace="~{fragments/forms::inputRow(object='authentication', field='password', type='password')}" />
                <input type="submit" th:value="#{authentication.login.headline}" class="btn btn-primary mt-4" />
            </form>
        </div>
    </body>
</html>
로그인 후 복사

As Thymeleaf doesn't allow direct access to request object anymore, we're providing the requestUri in the model.

@ModelAttribute("requestUri")
String getRequestServletPath(final HttpServletRequest request) {
    return request.getRequestURI();
}
로그인 후 복사

_  Providing the requestUri - as part of the AuthenticationController or a general ControllerAdvice _

With this template we send a POST request to the /login endpoint. The INFO or ERROR messages are automatically displayed by the layout. All used messages have to be present in our messages.properties.

authentication.login.headline=Login
authentication.email.label=Email
authentication.password.label=Password
authentication.login.required=Please login to access this area.
authentication.login.error=Your login was not successful - please try again.
authentication.logout.success=Your logout was successful.
navigation.login=Login
navigation.logout=Logout
로그인 후 복사

Last we can extend our layout.html. With this we also always show a login / logout link in the header. Spring Security also automatically provides a /logout endpoint, but we have to address it via POST.

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
            xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
    <!-- ... -->    
    <a sec:authorize="!isAuthenticated()" th:href="@{/login}" class="nav-link">[[#{navigation.login}]]</a>
    <form sec:authorize="isAuthenticated()" th:action="@{/logout}" method="post" class="nav-link">
        <input th:value="#{navigation.logout}" type="submit" class="unset" />
    </form>
    <!-- ... -->
</html>
로그인 후 복사

  Adding login / logout links to our layout

In the html tag we've extended the namespace to use the helpers from the thymeleaf-extras-springsecurity6 module. As a final step we only need to add the annotation @PreAuthorize("hasAuthority('ROLE_USER')") at our TodoListController.

Starting our application

With this we have all needed pieces of our puzzle together! Now we start our application and when we want to see the todo lists, we should be redirected to the login page. Here we can log in with test@test.com / testtest.

Form Login with Spring Boot and Thymeleaf
  Automatic redirect to the login

In the Free plan of Bootify, Spring Boot prototypes with its own database schema, REST API and frontend can be generated. In the Professional plan, among other things, Spring Security with the form-based login is available to generate the setup described here - exactly matching the created database and the selected settings. A registration endpoint and role source can be specified as well.

» See Features and Pricing

위 내용은 Spring Boot 및 Thymeleaf를 사용한 양식 로그인의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!