Selamat siang
Artikel ini akan mencakup pembuatan aplikasi web sederhana menggunakan Spring Boot dan Spring Security. Aplikasi akan menerapkan pendaftaran pengguna baru dan otorisasi, membatasi akses ke halaman situs tergantung pada peran pengguna.
Tujuan utama artikel ini adalah untuk menunjukkan bagaimana Anda dapat membatasi akses ke berbagai halaman situs untuk pengguna dengan peran yang berbeda.
Apa yang akan menjadi aplikasi?
Situs web dengan halaman-halaman berikut:
- halaman yang dapat diakses oleh semua pengguna: rumah, registrasi dan login;
- halaman tersedia untuk pengguna terdaftar: berita;
- halaman admin tersedia.
Apa yang akan kita gunakan
- JDK 8+;
- Ide Intellij;
- Spring (Spring Boot, Spring MVC, Spring Security);
- Hibernasi
- JSP
- PostgreSQL
Isi
- Deskripsi anotasi utama yang digunakan.
- Buat proyek baru di IDE.
- Membuat struktur proyek (paket).
- Menambahkan entitas, pengontrol, layanan, repositori, dan tampilan.
- Peluncuran Aplikasi.
1. Deskripsi anotasi utama yang digunakan
Kontroler adalah jenis kelas khusus yang digunakan dalam aplikasi MVC. Itu tampak seperti servlet HttpServlet biasa yang bekerja dengan objek HttpServletRequest dan HttpServletResponse, tetapi dengan fitur-fitur canggih dari Spring Framework.
Repositori - menunjukkan bahwa kelas digunakan untuk menentukan daftar
pekerjaan yang diperlukan untuk mencari, mengambil, dan menyimpan data. Anotasi dapat digunakan untuk mengimplementasikan template DAO.
Layanan - menunjukkan bahwa kelas adalah layanan untuk mengimplementasikan logika bisnis.
Konfigurasi - anotasi ini digunakan untuk kelas yang mendefinisikan komponen bean.
Autowired - anotasi memungkinkan Anda untuk secara otomatis mengatur nilai bidang. Fungsionalitas anotasi ini adalah bahwa kita tidak perlu khawatir tentang cara terbaik untuk mentransmisikan ke Bean contoh dari Bean lain. Spring sendiri akan menemukan Bean yang diinginkan dan mengganti nilainya di properti yang ditandai dengan anotasi.
Sedikit informasi tentang Spring Security
Objek paling mendasar adalah
SecurityContextHolder . Ini menyimpan informasi tentang konteks keamanan aplikasi saat ini, yang mencakup informasi terperinci tentang pengguna (prinsipal) yang bekerja dengan aplikasi tersebut. Keamanan Musim Semi menggunakan objek
Otentikasi , pengguna sesi resmi.
"Pengguna" hanyalah sebuah Objek. Dalam kebanyakan kasus, itu bisa terjadi
dilemparkan ke kelas
UserDetails .
UserDetails dapat dianggap sebagai adaptor antara database pengguna dan apa yang dibutuhkan Spring Security di dalam
SecurityContextHolder .
Untuk membuat
UserDetails , antarmuka
UserDetailsService digunakan, dengan metode tunggal:
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
2. Membuat proyek baru di IDE
Kami akan menggunakan sistem build Maven.
GroupId berarti pengidentifikasi unik perusahaan (atau nama domain pribadi Anda) yang merilis proyek.
ArtefactId hanyalah nama dari proyek kami.

Setelah pembuatan proyek selesai, file pom.xml
terbuka , Ide akan menawarkan untuk mengaktifkan impor otomatis - jangan menolak. File ini akan berisi semua dependensi (pustaka) yang digunakan dalam proyek.

3. Membuat struktur proyek (paket)
Segera beralih ke membuat paket. Struktur proyek, yang seharusnya berubah, ditunjukkan di bawah ini.

Sekarang secara singkat tentang apa yang akan disimpan dalam setiap paket:
- src \ main \ java \ com \ boots \ config - kelas dengan konfigurasi untuk MVC (MvcConfig) dan keamanan (WebSecurityConfig);
- src \ main \ java \ com \ boots \ controller - kelas dengan pengontrol;
- src \ main \ java \ com \ boots \ entitas - kelas dengan model;
- src \ main \ java \ com \ boots \ repository - antarmuka repositori ;
- src \ main \ java \ com \ boots \ service - kelas dengan layanan untuk model;
- src \ main \ webapp \ resources - objek statis: js, css, img;
- src \ main \ webapp \ WEB-INF \ jsp - representasi dalam bentuk file .jsp.
Pertimbangkan file
pom.xml . Di file ini, Anda perlu menentukan tautan ke file induk menggunakan tag
induk , mis. semua properti dan dependensi induk akan ditambahkan ke file anak ini.
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.9.RELEASE</version> </parent>
Selanjutnya, tambahkan dependensi untuk modul Spring, driver database PostgreSQL, server Tomcat, JSTL.
<properties> <java.version>1.8</java.version> </properties>
Secara default, maven akan menggunakan versi lama java 1.6, untuk memperbaikinya kami menentukan versi secara eksplisit.
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</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-data-jpa</artifactId> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.2.8</version> <scope>runtime</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <version>9.0.27</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>5.2.0.RELEASE</version> </dependency> </dependencies>
Kami juga menambahkan plugin yang memungkinkan Anda untuk mengemas jar atau arsip perang dan menjalankannya "di tempat":
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
Pom.xml penuh <?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> <groupId>ark</groupId> <artifactId>spring</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</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-data-jpa</artifactId> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <version>9.0.27</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>5.2.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies> <properties> <java.version>1.8</java.version> </properties> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Isi file
application.properties . 3 baris pertama berisi data untuk menghubungkan ke database (nama database adalah "spring", login dan kata sandi). 2 baris terakhir menunjukkan jalur ke file .jsp:
spring.datasource.url=jdbc:postgresql://localhost/spring spring.datasource.username=postgres spring.datasource.password=password spring.jpa.show-sql=true spring.jpa.generate-ddl=false spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true spring.mvc.view.prefix = /WEB-INF/jsp/ spring.mvc.view.suffix = .jsp
Properti
spring.jpa.show-sql menampilkan badan query database ke konsol.
spring.jpa.hibernate.ddl-auto memungkinkan Anda menetapkan strategi untuk membuat basis data berdasarkan model kami; ia memiliki nilai yang berbeda (tidak ada, buat, perbarui, dll.).
pembaruan dalam hal ini berarti bahwa tabel dan bidang basis data akan dibuat berdasarkan model kami dan akan berubah dengan mereka.
Ke depan, kita hanya perlu membuat database dengan nama
pegas , dan tabel pengguna, peran dan tabel tautannya bersama dengan kunci asing akan dihasilkan secara otomatis berdasarkan model (paket entitas), yang sekarang akan kita lanjutkan untuk membuat.
4. Menambahkan entitas, pengontrol, layanan, repositori, dan tampilan
4.1. Menambahkan Entitas (Model)
Persyaratan wajib untuk semua entitas: bidang pribadi, getter, dan setter untuk semua bidang, dan konstruktor kosong (tidak diperlihatkan dalam contoh). Mereka tidak perlu ditulis secara manual, tekan Alt + Sisipkan dan Ide akan melakukannya untuk Anda.
Untuk mengimpor kelas dan pustaka yang diperlukan, gunakan pintasan keyboard Alt + Enter .

Pengguna @Entity @Table(name = "t_user") public class User implements UserDetails { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Size(min=2, message = " 5 ") private String username; @Size(min=2, message = " 5 ") private String password; @Transient private String passwordConfirm; @ManyToMany(fetch = FetchType.EAGER) private Set<Role> roles; public User() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Override public String getUsername() { return username; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } public void setUsername(String username) { this.username = username; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return getRoles(); } @Override public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getPasswordConfirm() { return passwordConfirm; } public void setPasswordConfirm(String passwordConfirm) { this.passwordConfirm = passwordConfirm; } public Set<Role> getRoles() { return roles; } public void setRoles(Set<Role> roles) { this.roles = roles; } }
Pengguna Di awal tentang anotasi:
Entitas mengatakan bahwa bidang kelas memiliki peta dalam database,
Tabel (nama = "t_user") menunjukkan tabel mana.
Parameter
GenerationType.IDENTITY IDENTITY berarti bahwa basis data akan terlibat dalam menghasilkan id. Ada strategi lain. SEQUENCE - menggunakan mesin basis data bawaan, seperti PostgreSQL atau Oracle, mekanisme untuk menghasilkan nilai sekuensial (berurutan). TABEL - menggunakan tabel terpisah dengan nilai kunci yang diinisialisasi. Opsi lain adalah AUTO, hibernate sendiri akan memilih salah satu dari strategi di atas, tetapi disarankan untuk menentukan strategi secara eksplisit.
Bidang di bawah
annotasi Transient tidak memiliki tampilan dalam database. Daftar peran dikaitkan dengan pengguna, hubungan banyak ke banyak (satu pengguna dapat memiliki beberapa peran di satu sisi dan satu peran dapat memiliki beberapa pengguna di sisi lain);
FetchType.EAGER -
unduhan "serakah", mis. daftar peran dimuat segera dengan pengguna (jangan menunggu sampai mereka dihubungi).
Untuk menggunakan lebih lanjut kelas
Pengguna di Spring Security, ia harus mengimplementasikan antarmuka
UserDetails . Untuk melakukan ini, timpa semua metodenya. Namun dalam contoh kami, kami hanya akan menggunakan metode
getAuthorities () , ia mengembalikan daftar peran pengguna. Oleh karena itu, untuk metode yang tersisa, ubah nilai kembali ke
true .
Peran @Entity @Table(name = "t_role") public class Role implements GrantedAuthority { @Id private Long id; private String name; @Transient @ManyToMany(mappedBy = "roles") private Set<User> users; public Role() { } public Role(Long id) { this.id = id; } public Role(Long id, String name) { this.id = id; this.name = name; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<User> getUsers() { return users; } public void setUsers(Set<User> users) { this.users = users; } @Override public String getAuthority() { return getName(); } }
Peran Kelas ini harus mengimplementasikan antarmuka
GrantedAuthority , di mana hanya satu
getAuthority () metode yang perlu didefinisikan ulang (mengembalikan nama peran). Nama peran harus cocok dengan pola: "ROLE_NAME", misalnya,
ROLE_USER . Selain konstruktor default, Anda harus menambahkan beberapa konstruktor publik lainnya: id pertama hanya menerima, id kedua dan nama.
Di sini Anda dapat menambahkan batasan bidang.
Ukuran (min = 2) - berarti panjang minimum bidang adalah 2, jika batasan dilanggar, pesan akan ditampilkan.
4.2. Menerapkan lapisan akses data dan lapisan layanan
Spring Data menyediakan satu set implementasi yang siap pakai untuk membuat layer yang menyediakan akses ke database. Antarmuka
JpaRepository menyediakan serangkaian metode standar (findBy, save, deleteById, dll.) Untuk bekerja dengan database.
Gudang Pengguna. Kami membuat antarmuka pengguna dalam paket repositori dan mewarisi
JpaRepository <User, Long> , tentukan kelas
Pengguna dan jenis id-nya
Long .
public interface UserRepository extends JpaRepository<User, Long> { User findByUsername(String username); }
T.O. cukup dengan membuat antarmuka dan mewarisi
JpaRepository, Anda dapat melakukan kueri basis data standar. Jika Anda memerlukan metode tertentu, tambahkan saja ke antarmuka, berdasarkan kiat Ide. Sebagai contoh, kita memerlukan metode untuk mencari pengguna dalam database dengan nama. Kami menulis jenis objek yang dikembalikan, dan kemudian IDE menawarkan opsi yang memungkinkan. Yaitu dalam hal ini, nama metode menentukan badan permintaan.

Jika perlu, Anda dapat menggunakan anotasi
Permintaan atas metode dan menulis kueri dalam HQL atau SQL (Anda perlu menambahkan nativeQuery = true).
@Query(value = "SELECT nextval(pg_get_serial_sequence('t_user', 'id'))", nativeQuery = true) Long getNextId();
RoleRepository. Kami membuat dengan cara yang sama, kami tidak perlu metode kami sendiri di sini.
public interface RoleRepository extends JpaRepository<Role, Long> { }
Layanan Pengguna. Berisi metode untuk logika bisnis aplikasi. Kelas ini mengimplementasikan antarmuka
UserDetailsService (diperlukan untuk Spring Security), di mana Anda perlu mengganti satu
loadUserByUsername () method.
Di kelas ini, Anda bisa melihat cara lain untuk menjalankan kueri SQL - menggunakan EntityManager.
Layanan pengguna @Service public class UserService implements UserDetailsService { @PersistenceContext private EntityManager em; @Autowired UserRepository userRepository; @Autowired RoleRepository roleRepository; @Autowired BCryptPasswordEncoder bCryptPasswordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username); if (user == null) { throw new UsernameNotFoundException("User not found"); } return user; } public User findUserById(Long userId) { Optional<User> userFromDb = userRepository.findById(userId); return userFromDb.orElse(new User()); } public List<User> allUsers() { return userRepository.findAll(); } public boolean saveUser(User user) { User userFromDB = userRepository.findByUsername(user.getUsername()); if (userFromDB != null) { return false; } user.setRoles(Collections.singleton(new Role(1L, "ROLE_USER"))); user.setPassword(bCryptPasswordEncoder.encode(user.getPassword())); userRepository.save(user); return true; } public boolean deleteUser(Long userId) { if (userRepository.findById(userId).isPresent()) { userRepository.deleteById(userId); return true; } return false; } public List<User> usergtList(Long idMin) { return em.createQuery("SELECT u FROM User u WHERE u.id > :paramId", User.class) .setParameter("paramId", idMin).getResultList(); } }
Pertimbangkan metode
saveUser (Pengguna pengguna) .
public boolean saveUser(User user) { User userFromDB = userRepository.findByUsername(user.getUsername()); if (userFromDB != null) { return false; } user.setRoles(Collections.singleton(new Role(1L, "ROLE_USER"))); user.setPassword(bCryptPasswordEncoder.encode(user.getPassword())); userRepository.save(user); return true; }
Pertama, pencarian dilakukan dalam database dengan nama pengguna, jika pengguna dengan nama yang sama sudah ada, metode selesai bekerja. Jika nama pengguna tidak diambil, peran ROLE_USER ditambahkan. Agar tidak menyimpan kata sandi dalam bentuk mentah, sebelumnya hash menggunakan
bCryptPasswordEncoder . Kemudian pengguna baru disimpan dalam database.
4.3. Menambahkan pengontrol
Untuk halaman yang tidak diproses oleh server dengan cara apa pun, tetapi cukup mengembalikan halaman tersebut, pemetaan dapat dikonfigurasi dalam konfigurasi. Halaman
login ditangani oleh pengontrol Spring Security secara default, jadi pengontrol terpisah tidak diperlukan untuk itu.
@Configuration public class MvcConfig implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/login").setViewName("login"); registry.addViewController("/news").setViewName("news"); } }
RegistrasiKontroler. Kontroler terpisah diperlukan untuk halaman pendaftaran. Untuk memproses permintaan GET, penjelasan
@GetMapping ("/ registrasi") digunakan , untuk POST -
@PostMapping ("/ registrasi") .
RegistrasiKontroler @Controller public class RegistrationController { @Autowired private UserService userService; @GetMapping("/registration") public String registration(Model model) { model.addAttribute("userForm", new User()); return "registration"; } @PostMapping("/registration") public String addUser(@ModelAttribute("userForm") @Valid User userForm, BindingResult bindingResult, Model model) { if (bindingResult.hasErrors()) { return "registration"; } if (!userForm.getPassword().equals(userForm.getPasswordConfirm())){ model.addAttribute("passwordError", " "); return "registration"; } if (!userService.saveUser(userForm)){ model.addAttribute("usernameError", " "); return "registration"; } return "redirect:/"; } }
Untuk menambah atau mendapatkan sesuatu dari halaman, kita beralih ke model. Dalam permintaan GET, objek kosong baru kelas
Pengguna ditambahkan ke halaman. Hal ini dilakukan agar tidak mendapatkan data dari formulir pendaftaran satu per satu selama permintaan POST (nama pengguna, kata sandi, kata sandiComfirm), tetapi segera mendapatkan objek userForm yang diisi.
Metode
addUser () mengharapkan sebagai parameter objek pengguna (userForm) yang ditambahkan selama permintaan GET. Annotation
Valid memeriksa untuk melihat apakah batasan yang diberlakukan pada bidang dipenuhi, dalam hal ini setidaknya 2 karakter. Jika batasan tidak dipenuhi, maka
bindingResult akan mengandung kesalahan.
Jika kata sandi dan konfirmasinya tidak cocok, tambahkan pesan ke halaman dan kembalikan. Pada akhirnya, kami mencoba menyimpan menambahkan pengguna ke database.
Metode
saveUser () mengembalikan false jika pengguna dengan nama yang sama sudah ada dan benar jika pengguna disimpan dalam database. Jika upaya simpan gagal, kami menambahkan pesan kesalahan dan mengembalikan halaman. Jika pengguna berhasil disimpan, buka halaman utama.
Admincontroller Hanya pengguna admin yang memiliki akses ke halaman admin. Tidak ada yang baru dalam metode
userList () , ia menerima data dari semua pengguna dan menambahkannya ke halaman.
Admincontroller @Controller public class AdminController { @Autowired private UserService userService; @GetMapping("/admin") public String userList(Model model) { model.addAttribute("allUsers", userService.allUsers()); return "admin"; } @PostMapping("/admin") public String deleteUser(@RequestParam(required = true, defaultValue = "" ) Long userId, @RequestParam(required = true, defaultValue = "" ) String action, Model model) { if (action.equals("delete")){ userService.deleteUser(userId); } return "redirect:/admin"; } @GetMapping("/admin/gt/{userId}") public String gtUser(@PathVariable("userId") Long userId, Model model) { model.addAttribute("allUsers", userService.usergtList(userId)); return "admin"; } }
Metode
deleteUser () menggunakan anotasi
RequestParam i.e. tampilan akan memiliki formulir yang harus melewati dua parameter - userId dan tindakan. Tautan akan berupa
http: // localhost: 8080 / admin? UserId = 24 & action = delete ketika permintaan ini dieksekusi, pengguna dengan id = 24 akan dihapus.
Opsi lain untuk meneruskan parameter ke URL adalah menggunakan
PathVariable . Dengan menggunakan anotasi ini, kita mendapatkan bagian-bagian dari URL, untuk metode
getUser () , URL akan terlihat seperti ini:
http: // localhost: 8080 / admin / gt / 24 , setelah transisi, daftar semua pengguna dengan id> 24 akan ditampilkan.
Pengaturan keamananWebSecurityConfig. Berisi 2
kacang BCryptPasswordEncoder dan
AuthenticationManager , yang sebelumnya bertemu di kelas userService.
Selain itu, metode
configure () mengkonfigurasi akses ke berbagai sumber daya situs. Sebagai parameter dari metode
antMatchers () ,
kami melewati jalur yang ingin kami tetapkan batasnya. Kemudian kami menunjukkan kepada pengguna dengan peran apa halaman ini akan tersedia.
WebSecurityConfig @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired UserService userService; @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity .csrf() .disable() .authorizeRequests()
4.4. Menambahkan Tampilan
Halaman beranda
index.jsp , di bawah ini adalah 2 opsi - untuk tamu dan pengguna resmi.


index.jsp <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE HTML> <html> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <link rel="stylesheet" type="text/css" href="${contextPath}/resources/css/style.css"> </head> <body> <div> <h3>${pageContext.request.userPrincipal.name}</h3> <sec:authorize access="!isAuthenticated()"> <h4><a href="/login"></a></h4> <h4><a href="/registration"></a></h4> </sec:authorize> <sec:authorize access="isAuthenticated()"> <h4><a href="/logout"></a></h4> </sec:authorize> <h4><a href="/news"> ( )</a></h4> <h4><a href="/admin"> ( )</a></h4> </div> </body> </html>
Untuk menyembunyikan bagian dari konten pada halaman untuk pengguna yang berwenang (tautan ke halaman registrasi dan otorisasi), Anda dapat menggunakan tag
otorisasi dari pustaka tag Spring Security. Parameter akses menerima beberapa ekspresi, misalnya, Anda dapat menetapkan batasan tergantung pada peran pengguna
hasRole ('ADMIN') .
registrasi.jsp Halaman registrasi.

registrasi.jsp <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div> <form:form method="POST" modelAttribute="userForm"> <h2></h2> <div> <form:input type="text" path="username" placeholder="Username" autofocus="true"></form:input> <form:errors path="username"></form:errors> ${usernameError} </div> <div> <form:input type="password" path="password" placeholder="Password"></form:input> </div> <div> <form:input type="password" path="passwordConfirm" placeholder="Confirm your password"></form:input> <form:errors path="password"></form:errors> ${passwordError} </div> <button type="submit"></button> </form:form> <a href="/"></a> </div> </body> </html>
Pada halaman ini, tag form digunakan dari pustaka tag, dengan bantuannya atribut model userForm dibundel (kami menambahkannya ke halaman selama permintaan GET dalam controller) dan form:
<form:form method="POST" modelAttribute="userForm">
Anda juga harus menentukan jalur untuk mengikat properti userForm:
<form:input type="text" path="username" placeholder="Username"></form:input>
login.jsp Halaman
login .

login.jsp <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Log in with your account</title> </head> <body> <sec:authorize access="isAuthenticated()"> <% response.sendRedirect("/"); %> </sec:authorize> <div> <form method="POST" action="/login"> <h2> </h2> <div> <input name="username" type="text" placeholder="Username" autofocus="true"/> <input name="password" type="password" placeholder="Password"/> <button type="submit">Log In</button> <h4><a href="/registration"></a></h4> </div> </form> </div> </body> </html>
Halaman ini, sebagaimana telah disebutkan, ditangani oleh pengontrol Spring secara default. Penting untuk menentukan tindakan:
action = "/ login" dan nama input.
admin.jsp halaman
admin .

admin.jsp <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Log in with your account</title> <link rel="stylesheet" type="text/css" href="${contextPath}/resources/css/style.css"> </head> <body> <div> <table> <thead> <th>ID</th> <th>UserName</th> <th>Password</th> <th>Roles</th> </thead> <c:forEach items="${allUsers}" var="user"> <tr> <td>${user.id}</td> <td>${user.username}</td> <td>${user.password}</td> <td> <c:forEach items="${user.roles}" var="role">${role.name}; </c:forEach> </td> <td> <form action="${pageContext.request.contextPath}/admin" method="post"> <input type="hidden" name="userId" value="${user.id}"/> <input type="hidden" name="action" value="delete"/> <button type="submit">Delete</button> </form> </td> </tr> </c:forEach> </table> <a href="/"></a> </div> </body> </html>
news.jsp Halaman berita statis. Ini hanya digunakan untuk menunjukkan hak-hak pengguna, jadi konten pilihan Anda.
news.jsp <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div> <h2> <br> .</h2> <a href="/"></a> </div> </body> </html>
5. Meluncurkan aplikasi
Di kelas Aplikasi utama, tambahkan berikut ini: @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Sebelum melanjutkan ke langkah berikutnya, pastikan bahwa struktur proyek Anda cocok dengan yang disajikan di awal.Saatnya untuk membuat database kosong bernama spring , Anda perlu melakukan ini sebelum aplikasi pertama diluncurkan dan hanya sekali.Anda dapat menjalankan aplikasi dan melihat bagaimana perubahan database - 3 tabel kosong akan dibuat di dalamnya. Anda perlu menambahkan peran pengguna ke tabel t_role:SQL query menambahkan peran INSERT INTO public.t_role(id, name) VALUES (1, 'ROLE_USER'), (2, 'ROLE_ADMIN');
Sekarang Anda dapat mencoba mendaftar. Aplikasi tidak menyediakan metode untuk mendaftarkan pengguna administrator, tetapi diperlukan untuk demonstrasi. Oleh karena itu, setelah mendaftarkan pengguna baru, tambahkan entri ke tabel peran pengguna yang memberikan peran ini:Permintaan SQL menambahkan peran admin INSERT INTO public.t_user_roles(user_id, roles_id) VALUES (1, 2);
Jika setelah menambahkan hak administrator Anda tidak dapat mengakses halaman administrator (kesalahan 403), pergi ke situs web. Hanya pengguna dengan peran administrator yang memiliki akseske halaman http: // localhost: 8080 / admin . http: // localhost: 8080 / berita yang akan dilihat oleh pengguna terdaftar. Anda juga dapat mencoba masuk ke halaman registrasi dan login, diotorisasi di situs.Kesimpulan
Akibatnya, aplikasi web dibuat di mana kami dapat mengontrol akses pengguna ke halaman situs menggunakan peran. Anda dapat menetapkan beberapa peran untuk satu pengguna. Misalnya, saat mendaftarkan pengguna baru, kami menambahkan peran Pengguna, yang merupakan dasar untuk semua orang, dan kemudian ketika meminta hak tambahan tambahan oleh pengguna, kami dapat memberinya peran Penulis, yang akan memungkinkannya untuk menambahkan berita baru ke situs.File css dan js dibuat, tetapi isinya tidak disajikan. Jika diinginkan, Anda dapat menambahkan desain, misalnya, menggunakan Bootstrap dan interaktivitas menggunakan js.Unduh proyek yang sudah selesai.Sumber yang digunakan
- Registrasi dan Login dengan Spring Boot, Spring Security, Spring Data JPA, Hibernate, MySQL, JSP, Bootstrap dan Docker Compose
- Sisi lain dari Spring
- Ulasan Teknis Keamanan Musim Semi / Keamanan Musim Semi
- Spring
- : Spring 3 MVC + Spring Security + Hibernate