Spring security series

This commit is contained in:
javadevjournal
2020-09-08 15:49:28 -07:00
parent 57cba77bd6
commit d2490de509
15 changed files with 125 additions and 74 deletions

View File

@@ -69,6 +69,13 @@
<version>3.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity5 -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -57,7 +57,6 @@
<orderEntry type="library" name="Maven: org.thymeleaf:thymeleaf:3.0.11.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.attoparser:attoparser:2.0.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.unbescape:unbescape:1.1.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.30" level="project" />
<orderEntry type="library" name="Maven: org.thymeleaf.extras:thymeleaf-extras-java8time:3.0.4.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-jpa:2.3.1.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-aop:2.3.1.RELEASE" level="project" />
@@ -77,13 +76,19 @@
<orderEntry type="library" name="Maven: org.glassfish.jaxb:jaxb-runtime:2.3.3" level="project" />
<orderEntry type="library" name="Maven: org.glassfish.jaxb:txw2:2.3.3" level="project" />
<orderEntry type="library" name="Maven: com.sun.istack:istack-commons-runtime:3.0.11" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.sun.activation:jakarta.activation:1.2.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-jpa:2.3.1.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:2.3.1.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-orm:5.2.7.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-tx:5.2.7.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aspects:5.2.7.RELEASE" level="project" />
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:8.0.18" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-mail:2.3.1.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.2.7.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.sun.mail:jakarta.mail:1.6.5" level="project" />
<orderEntry type="library" name="Maven: com.sun.activation:jakarta.activation:1.2.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.11" level="project" />
<orderEntry type="library" name="Maven: org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.30" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-starter-test:2.3.1.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test:2.3.1.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test-autoconfigure:2.3.1.RELEASE" level="project" />

View File

@@ -37,4 +37,4 @@ public class DefaultEmailService implements EmailService{
mimeMessageHelper.setText(emailContent, true);
emailSender.send(message);
}
}
}

View File

@@ -10,8 +10,11 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import javax.annotation.Resource;
import javax.sql.DataSource;
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
@@ -22,18 +25,27 @@ public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
PasswordEncoder passwordEncoder;
@Autowired
private DataSource dataSource;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login", "/register")
.permitAll()
.antMatchers("/account/**").hasAuthority("USER")
.and()
.rememberMe().tokenRepository(persistentTokenRepository())
.and()
.formLogin(form -> form
.defaultSuccessUrl("/account/home")
.loginPage("/login")
.failureUrl("/login?error=true")
)
.logout(logout->logout
.deleteCookies("dummyCookie")
);
}
@Override
@@ -55,5 +67,10 @@ public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
auth.authenticationProvider(authProvider());
}
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
db.setDataSource(dataSource);
return db;
}
}

View File

@@ -9,7 +9,7 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
@Service("userDetailsService")
public class CustomUserDetailService implements UserDetailsService{
@Autowired

View File

@@ -5,7 +5,6 @@ import org.hibernate.annotations.CreationTimestamp;
import javax.persistence.*;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDateTime;
@Entity

View File

@@ -51,6 +51,7 @@ public class DefaultUserService implements UserService{
encodePassword(user, userEntity);
userRepository.save(userEntity);
sendRegistrationConfirmationEmail(userEntity);
}
@Override
@@ -58,17 +59,13 @@ public class DefaultUserService implements UserService{
return userRepository.findByEmail(email)!=null ? true : false;
}
private void encodePassword(UserData source, UserEntity target){
target.setPassword(passwordEncoder.encode(source.getPassword()));
}
@Override
public void sendRegistrationConfirmationEmail(UserEntity userEntity){
SecureToken secureToken = secureTokenService.createSecureToken();
secureToken.setUser(userEntity);
public void sendRegistrationConfirmationEmail(UserEntity user) {
SecureToken secureToken= secureTokenService.createSecureToken();
secureToken.setUser(user);
secureTokenRepository.save(secureToken);
AccountVerificationEmailContext emailContext = new AccountVerificationEmailContext();
emailContext.init(userEntity);
emailContext.init(user);
emailContext.setToken(secureToken.getToken());
emailContext.buildVerificationUrl(baseURL, secureToken.getToken());
try {
@@ -76,6 +73,7 @@ public class DefaultUserService implements UserService{
} catch (MessagingException e) {
e.printStackTrace();
}
}
@Override
@@ -95,4 +93,10 @@ public class DefaultUserService implements UserService{
secureTokenService.removeToken(secureToken);
return true;
}
private void encodePassword(UserData source, UserEntity target){
target.setPassword(passwordEncoder.encode(source.getPassword()));
}
}

View File

@@ -4,12 +4,23 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
@Controller
@RequestMapping("/account")
public class HomeController {
@GetMapping("/home")
public String home(){
public String home(HttpServletResponse response){
setDummyCookie(response);
return "index";
}
private void setDummyCookie(HttpServletResponse response){
Cookie cookie = new Cookie("dummyCookie", "dummy_cookie");
cookie.setMaxAge(2592000);
cookie.setPath("/");
response.addCookie(cookie);
}
}

View File

@@ -58,12 +58,12 @@ public class RegistrationController {
@GetMapping("/verify")
public String verifyCustomer(@RequestParam(required = false) String token, final Model model, RedirectAttributes redirAttr){
if(StringUtils.isEmpty(token)){
redirAttr.addFlashAttribute("tokenError", messageSource.getMessage("user.registration.verification.missing.token", null,LocaleContextHolder.getLocale()));
return REDIRECT_LOGIN;
}
if(StringUtils.isEmpty(token)){
redirAttr.addFlashAttribute("tokenError", messageSource.getMessage("user.registration.verification.missing.token", null,LocaleContextHolder.getLocale()));
return REDIRECT_LOGIN;
}
try {
userService.verifyUser(token);
userService.verifyUser(token);
} catch (InvalidTokenException e) {
redirAttr.addFlashAttribute("tokenError", messageSource.getMessage("user.registration.verification.invalid.token", null,LocaleContextHolder.getLocale()));
return REDIRECT_LOGIN;
@@ -72,4 +72,5 @@ public class RegistrationController {
redirAttr.addFlashAttribute("verifiedAccountMsg", messageSource.getMessage("user.registration.verification.success", null,LocaleContextHolder.getLocale()));
return REDIRECT_LOGIN;
}
}

View File

@@ -1,6 +1,6 @@
#Enable below property to check what all Spring security filters are configured and used by Spring security.This can also help
# to get better understanding as how security filters work internally.
logging.level.org.springframework.security.web.FilterChainProxy=DEBUG
#logging.level.org.springframework.security.web.FilterChainProxy=DEBUG
#database configuration.Change these based on your setup
spring.jpa.generate-ddl=true
@@ -19,3 +19,10 @@ jdj.secure.token.validity = 28800
site.base.url.http=http://localhost:8080
site.base.url.https=http://localhost:8080
spring.mail.host=test
spring.mail.port=25
spring.mail.username=abc@dummy.com
spring.mail.password=test
#spring.mail.properties.mail.smtp.auth=true
#spring.mail.properties.mail.smtp.starttls.enable=true

View File

@@ -36,7 +36,7 @@
</div>
<div class="input-group mb-3">
<input type="email" class="form-control" name="username" placeholder="Email">
<input type="email" class="form-control" name="username" placeholder="Email" autocomplete=”off”>
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-envelope"></span>
@@ -55,7 +55,7 @@
<div class="row">
<div class="col-8">
<div class="icheck-primary">
<input type="checkbox" id="remember">
<input type="checkbox" id="remember" name="remember-me">
<label for="remember">
Remember Me
</label>

View File

@@ -18,4 +18,5 @@
<link rel="stylesheet" th:href="@{/dist/css/adminlte.min.css}">
<!-- Google Font: Source Sans Pro -->
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700" rel="stylesheet">
</head>

View File

@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<nav class="main-header navbar navbar-expand navbar-white navbar-light">
<!-- Left navbar links -->
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" data-widget="pushmenu" href="#" role="button"><i class="fas fa-bars"></i></a>
</li>
<li class="nav-item d-none d-sm-inline-block">
<a href="index.html" class="nav-link">Home</a>
</li>
<li class="nav-item d-none d-sm-inline-block">
<a href="#" class="nav-link">Contact</a>
</li>
</ul>
<!-- SEARCH FORM -->
<form class="form-inline ml-3">
<div class="input-group input-group-sm">
<input class="form-control form-control-navbar" type="search" placeholder="Search" aria-label="Search">
<div class="input-group-append">
<button class="btn btn-navbar" type="submit">
<i class="fas fa-search"></i>
</button>
</div>
</div>
</form>
<div sec:authorize="isAuthenticated()">
<header class="main-header">
<div class="navbar-custom-menu">
<ul class="navbar-nav">
<li class="dropdown user user-menu">
<!--<a th:href="@{/logout}">Logout</a> -->
<a href="javascript: document.logoutForm.submit()" class="dropdown-toggle">Sign out</a>
<form name="logoutForm" th:action="@{/logout}" method="post" th:hidden="true">
<input hidden type="submit" value="Sign Out"/>
</form>
</ul>
</div>
</header>
</div>
</nav>

View File

@@ -3,7 +3,7 @@
This is a starter template page. Use this page to start your new project from
scratch. This page gets rid of all links and provides the needed markup only.
-->
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<html xmlns:th="http://www.thymeleaf.org" lang="en" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head th:replace="core/header :: head"> <meta charset="utf-8">
</head>
<body class="hold-transition sidebar-mini">
@@ -43,8 +43,6 @@ scratch. This page gets rid of all links and provides the needed markup only.
<aside class="main-sidebar sidebar-dark-primary elevation-4">
<!-- Brand Logo -->
<a href="index3.html" class="brand-link">
<img src="dist/img/AdminLTELogo.png" alt="JavaDevJournal" class="brand-image img-circle elevation-3"
style="opacity: .8">
<span class="brand-text font-weight-light">JavaDevJournal</span>
</a>
@@ -80,7 +78,7 @@ scratch. This page gets rid of all links and provides the needed markup only.
Anything you want
</div>
<!-- Default to the left -->
<strong>Copyright &copy; 2014-2020 <a href="https://javadevjournal.com">Java Dev Journal</a>.</strong> All rights reserved.
<strong>Copyright &copy; 2014-2020 <a href="https://www.javadevjournal.com">Java Dev Journal</a>.</strong> All rights reserved.
</footer>
</div>
<!-- ./wrapper -->

View File

@@ -1,58 +1,16 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>JavaDevJournal | Learn Spring Security</title>
<!-- Font Awesome Icons -->
<link rel="stylesheet" th:href="@{/plugins/fontawesome-free/css/all.min.css}">
<!-- IonIcons -->
<link rel="stylesheet" href="http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
<!-- Theme style -->
<link rel="stylesheet" th:href="@{/dist/css/adminlte.min.css}">
<!-- Google Font: Source Sans Pro -->
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700" rel="stylesheet">
<head th:replace="core/header :: head"> <meta charset="utf-8">
</head>
<body class="hold-transition sidebar-mini">
<div class="wrapper">
<!-- Navbar -->
<nav class="main-header navbar navbar-expand navbar-white navbar-light">
<!-- Left navbar links -->
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" data-widget="pushmenu" href="#" role="button"><i class="fas fa-bars"></i></a>
</li>
<li class="nav-item d-none d-sm-inline-block">
<a href="index.html" class="nav-link">Home</a>
</li>
<li class="nav-item d-none d-sm-inline-block">
<a href="#" class="nav-link">Contact</a>
</li>
</ul>
<!-- SEARCH FORM -->
<form class="form-inline ml-3">
<div class="input-group input-group-sm">
<input class="form-control form-control-navbar" type="search" placeholder="Search" aria-label="Search">
<div class="input-group-append">
<button class="btn btn-navbar" type="submit">
<i class="fas fa-search"></i>
</button>
</div>
</div>
</form>
</nav>
<nav th:replace="core/userProfile :: nav"></nav>
<!-- /.navbar -->
<!-- Main Sidebar Container -->
<aside class="main-sidebar sidebar-dark-primary elevation-4">
<!-- Brand Logo -->
<a href="index.html" class="brand-link">
<img src="dist/img/AdminLTELogo.png" alt="AdminLTE Logo" class="brand-image img-circle elevation-3"
style="opacity: .8">
<span class="brand-text font-weight-light">Learn Spring Security</span>
</a>
@@ -60,9 +18,6 @@
<div class="sidebar">
<!-- Sidebar user panel (optional) -->
<div class="user-panel mt-3 pb-3 mb-3 d-flex">
<div class="image">
<img src="dist/img/user.png" class="img-circle elevation-2" alt="User Image">
</div>
<div class="info">
<a href="#" class="d-block">Java Dev Journal</a>
</div>