Spring security series
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -37,4 +37,4 @@ public class DefaultEmailService implements EmailService{
|
||||
mimeMessageHelper.setText(emailContent, true);
|
||||
emailSender.send(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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 © 2014-2020 <a href="https://javadevjournal.com">Java Dev Journal</a>.</strong> All rights reserved.
|
||||
<strong>Copyright © 2014-2020 <a href="https://www.javadevjournal.com">Java Dev Journal</a>.</strong> All rights reserved.
|
||||
</footer>
|
||||
</div>
|
||||
<!-- ./wrapper -->
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user