Boa tarde
Este artigo abordará a criação de um aplicativo Web simples usando o Spring Boot e o Spring Security. O aplicativo implementará o registro de novos usuários e a autorização, restringindo o acesso às páginas do site, dependendo da função do usuário.
O objetivo principal do artigo é mostrar como você pode restringir o acesso a várias páginas do site para usuários com funções diferentes.
Qual será o aplicativo?
Site com as seguintes páginas:
- páginas acessíveis a todos os usuários: home, registro e login;
- página disponível para usuários registrados: notícias;
- página de administração disponível.
O que vamos usar
- JDK 8+;
- Idea Intellij;
- Spring (Spring Boot, Spring MVC, Spring Security);
- Hibernate
- JSP
- PostgreSQL
Conteúdo
- Descrição das principais anotações utilizadas.
- Crie um novo projeto no IDE.
- Criando uma estrutura de projeto (pacotes).
- Adicionando entidades, controladores, serviços, repositórios e visualizações.
- Lançamento de aplicativo.
1. Descrição das principais anotações utilizadas
Controller é um tipo especial de classe usado em aplicativos MVC. Parece um servlet HttpServlet normal que funciona com os objetos HttpServletRequest e HttpServletResponse, mas com recursos avançados do Spring Framework.
Repositório - indica que a classe é usada para especificar a lista
trabalho necessário para pesquisar, recuperar e armazenar dados. A anotação pode ser usada para implementar o modelo DAO.
Serviço - indica que a classe é um serviço para implementar a lógica de negócios.
Configuração - essa anotação é usada para classes que definem componentes de bean.
Ligação automática - a anotação permite definir automaticamente o valor do campo. A funcionalidade desta anotação é que não precisamos nos preocupar com a melhor maneira de passar uma cópia de outro Bean para um Bean. A própria Spring encontrará o Bean desejado e substituirá seu valor na propriedade que está marcada com a anotação.
Um pouco de informação sobre Spring Security
O objeto mais fundamental é o
SecurityContextHolder . Ele armazena informações sobre o contexto de segurança atual do aplicativo, que inclui informações detalhadas sobre o usuário (principal) que trabalha com o aplicativo. O Spring Security usa um objeto de
autenticação , um usuário autorizado da sessão.
Um "usuário" é apenas um objeto. Na maioria dos casos, pode ser
convertido para a classe
UserDetails .
Os UserDetails podem ser vistos como um adaptador entre os bancos de dados do usuário e o que o Spring Security exige dentro do
SecurityContextHolder .
Para criar um
UserDetails , a interface
UserDetailsService é usada, com um único método:
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
2. Criando um novo projeto no IDE
Usaremos o sistema de compilação Maven.
GroupId significa o identificador exclusivo da empresa (ou seu nome de domínio pessoal) que libera o projeto.
ArtefactId é apenas o nome do nosso projeto.

Após a conclusão da criação do projeto, o arquivo pom.xml é
aberto , o Idea oferece a habilitação da importação automática - não recuse. Este arquivo conterá todas as dependências (bibliotecas) usadas no projeto.

3. Criando uma estrutura de projeto (pacotes)
Imediatamente, passe à criação de pacotes. A estrutura do projeto, que deve sair, é mostrada abaixo.

Agora, brevemente, sobre o que será armazenado em cada pacote:
- src \ main \ java \ com \ boots \ config - classes com configurações para MVC (MvcConfig) e segurança (WebSecurityConfig);
- src \ main \ java \ com \ boots \ controller - classes com controladores;
- src \ main \ java \ com \ boots \ entity - classes com modelos;
- src \ main \ java \ com \ boots \ repository - interfaces de repositório ;
- src \ main \ java \ com \ boots \ service - classes com serviços para modelos;
- src \ main \ webapp \ resources - objetos estáticos: js, css, img;
- src \ main \ webapp \ WEB-INF \ jsp - representações na forma de arquivos .jsp.
Considere o arquivo
pom.xml . Nesse arquivo, você precisa especificar um link para o arquivo pai usando a tag
pai , ou seja, todas as propriedades e dependências do pai serão adicionadas a esse arquivo filho.
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.9.RELEASE</version> </parent>
Em seguida, adicione as dependências dos módulos Spring, o driver de banco de dados PostgreSQL, servidor Tomcat, JSTL.
<properties> <java.version>1.8</java.version> </properties>
Por padrão, o maven usará a versão antiga do java 1.6. Para corrigir isso, especificamos a versão explicitamente.
<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>
Também adicionamos um plug-in que permite compactar arquivos jar ou war e executá-los "no local":
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
Pom.xml completo <?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>
Preencha o arquivo
application.properties . As três primeiras linhas contêm dados para conexão com o banco de dados (o nome do banco de dados é “primavera”, login e senha). As duas últimas linhas indicam o caminho para os arquivos .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
A propriedade
spring.jpa.show-sql exibe os corpos das consultas ao banco de dados no console.
O spring.jpa.hibernate.ddl-auto permite definir uma estratégia para criar um banco de dados com base em nossos modelos; possui valores diferentes (nenhum, criar, atualizar, etc.).
atualizar neste caso significa que as tabelas e os campos do banco de dados serão criados com base em nossos modelos e serão alterados com eles.
Olhando para o futuro, precisaremos apenas criar um banco de dados com o nome
spring , e as tabelas de usuário, funções e sua tabela de links, juntamente com chaves estrangeiras, serão geradas automaticamente com base nos modelos (pacote de entidades), que iremos agora criar.
4. Adicionando entidades, controladores, serviços, repositórios e visualizações
4.1 Adicionando entidades (modelos)
Um requisito obrigatório para todas as entidades: campos privados, getters e setters para todos os campos e um construtor vazio (não mostrado nos exemplos). Eles não precisam ser escritos manualmente, pressione Alt + Insert e o Idea fará isso por você.
Para importar as classes e bibliotecas necessárias, use o atalho de teclado Alt + Enter .

Usuário @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; } }
Usuário No início sobre anotações: A
entidade diz que os campos da classe têm um mapa no banco de dados,
Tabela (name = "t_user") indica qual tabela.
O parâmetro
GenerationType.IDENTITY IDENTITY significa que o banco de dados estará envolvido na geração do ID. Existem outras estratégias. SEQUENCE - usa o mecanismo de banco de dados embutido, como PostgreSQL ou Oracle, um mecanismo para gerar valores sequenciais (sequência). TABELA - usa uma tabela separada com valores-chave inicializados. Outra opção é AUTO, o próprio hibernate escolherá uma das estratégias acima, mas é recomendável especificar explicitamente a estratégia.
O campo na anotação
transitória não é exibido no banco de dados. A lista de funções está associada ao usuário, um relacionamento muitos para muitos (um usuário pode ter várias funções, por um lado, e uma função pode ter vários usuários, por outro);
FetchType.EAGER - download "ganancioso", ou seja, a lista de funções é carregada imediatamente com o usuário (não espera até que eles sejam contatados).
Para usar ainda mais a classe
User no Spring Security, ele deve implementar a interface
UserDetails . Para fazer isso, substitua todos os seus métodos. Porém, em nosso exemplo, usaremos apenas o método
getAuthorities () ; ele retornará uma lista de funções de usuário. Portanto, para os métodos restantes, altere o valor de retorno para
true .
Função @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(); } }
Função Essa classe deve implementar a interface
GrantedAuthority , na qual apenas um método
getAuthority () precisa ser redefinido (retorna o nome da função). O nome da função deve corresponder ao padrão: "ROLE_NAME", por exemplo,
ROLE_USER . Além do construtor padrão, você deve adicionar mais alguns construtores públicos: o primeiro aceita apenas ID, o segundo ID e nome.
Aqui você pode adicionar restrições de campo.
Tamanho (min = 2) - significa que o comprimento mínimo do campo é 2; se a restrição for violada, uma mensagem será exibida.
4.2 Implementando uma camada de acesso a dados e uma camada de serviço
O Spring Data fornece um conjunto de implementações prontas para criar uma camada que fornece acesso ao banco de dados. A interface
JpaRepository fornece um conjunto de métodos padrão (findBy, save, deleteById, etc.) para trabalhar com o banco de dados.
UserRepository. Criamos a interface do usuário no pacote do repositório e herdamos o
JpaRepository <User, Long> , especificamos a classe
User e seu tipo de ID é
Long .
public interface UserRepository extends JpaRepository<User, Long> { User findByUsername(String username); }
T.O. simplesmente criando uma interface e herdando o
JpaRepository, você pode executar consultas padrão no banco de dados. Se você precisar de um método específico, basta adicioná-lo à interface, com base nas dicas do Idea. Por exemplo, precisamos de um método para procurar um usuário em um banco de dados por nome. Escrevemos o tipo do objeto retornado e, em seguida, o IDE oferece opções possíveis. I.e. nesse caso, o nome do método determina o corpo da solicitação.

Se necessário, você pode usar a anotação de
Consulta sobre o método e gravar consultas em HQL ou SQL (você precisa adicionar nativeQuery = true).
@Query(value = "SELECT nextval(pg_get_serial_sequence('t_user', 'id'))", nativeQuery = true) Long getNextId();
RoleRepository. Criamos da mesma maneira, não precisamos de nossos próprios métodos aqui.
public interface RoleRepository extends JpaRepository<Role, Long> { }
UserService. Contém métodos para a lógica de negócios do aplicativo. Esta classe implementa a interface
UserDetailsService (necessária para o Spring Security), na qual você precisa substituir um método
loadUserByUsername () .
Nesta classe, você pode ver outra maneira de executar uma consulta SQL - usando o EntityManager.
Serviço ao usuário @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(); } }
Considere o
método saveUser (Usuário usuário) .
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; }
Primeiro, uma pesquisa é realizada no banco de dados pelo nome do usuário; se já existir um usuário com o mesmo nome, o método termina o trabalho. Se o nome de usuário não for usado, a função ROLE_USER será adicionada. Para não armazenar a senha em formato bruto, ela é previamente hash usando
bCryptPasswordEncoder . Em seguida, o novo usuário é salvo no banco de dados.
4.3 Adicionando controladores
Para páginas que não são processadas pelo servidor de forma alguma, mas simplesmente retornam a página, o mapeamento pode ser configurado na configuração. A página de
login é tratada pelo controlador Spring Security por padrão, portanto, um controlador separado não é necessário para ele.
@Configuration public class MvcConfig implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/login").setViewName("login"); registry.addViewController("/news").setViewName("news"); } }
RegistrationController. Um controlador separado é necessário para a página de registro. Para processar uma solicitação GET, a anotação
@GetMapping ("/ registration") é usada para POST -
@PostMapping ("/ registration") .
RegistrationController @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:/"; } }
Para adicionar ou obter algo da página, passamos ao modelo. Em uma solicitação GET, um novo objeto vazio da classe
User é adicionado à página. Isso é feito para não obter dados do formulário de registro, um de cada vez, durante uma solicitação POST (nome de usuário, senha, passwordComfirm), mas obter imediatamente o objeto userForm preenchido.
O método
addUser () espera como parâmetro o objeto de usuário (userForm) que foi adicionado durante a solicitação GET. Anotação
Válida verifica se as restrições definidas nos campos são cumpridas, neste caso com pelo menos 2 caracteres. Se as restrições não foram cumpridas,
bindingResult conterá erros.
Se a senha e sua confirmação não corresponderem, adicione uma mensagem à página e devolva-a. No final, tentamos salvar adicionar o usuário ao banco de dados.
O método
saveUser () retorna false se um usuário com o mesmo nome já existir e true se o usuário for salvo no banco de dados. Se a tentativa de salvar falhar, adicionamos uma mensagem de erro e retornamos a página. Se o usuário for salvo com sucesso, vá para a página principal.
Admincontroller Somente usuários administrativos têm acesso à página de administração. Não há nada novo no método
userList () ; ele recebe os dados de todos os usuários e os adiciona à página.
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"; } }
O método
deleteUser () usa a anotação
RequestParam, ou seja, a visualização terá um formulário que deve passar dois parâmetros - userId e action. O link terá o formato
http: // localhost: 8080 / admin? UserId = 24 & action = delete quando essa solicitação for executada, o usuário com id = 24 será excluído.
Outra opção para passar parâmetros para uma URL é usar
PathVariable . Usando esta anotação, obtemos as partes individuais da URL, para o método
getUser () , a URL terá a seguinte aparência:
http: // localhost: 8080 / admin / gt / 24 , após a transição, uma lista de todos os usuários com id> 24 será exibida.
Configurações de segurançaWebSecurityConfig. Contém 2
beans BCryptPasswordEncoder e
AuthenticationManager , que foram atendidos anteriormente na classe userService.
Além disso, o método
configure () configura o acesso a vários recursos do site. Como parâmetros do método
antMatchers () , passamos os caminhos para os quais queremos definir um limite. Em seguida, indicamos aos usuários com qual papel essa página / páginas estará disponível.
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 Adicionando vistas
index.jsp Página inicial, abaixo estão 2 opções - para um convidado e um usuário autorizado.


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>
Para ocultar parte do conteúdo da página para usuários autorizados (link para a página de registro e autorização), você pode usar a marca de
autorização na biblioteca de marcas do Spring Security. O parâmetro de acesso aceita várias expressões, por exemplo, você pode definir uma restrição dependendo da função do usuário
hasRole ('ADMIN') .
registration.jsp Página de registro.

registration.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>
Nesta página, a tag do formulário é usada na biblioteca de tags, com a ajuda do atributo do modelo userForm é vinculado (nós a adicionamos à página durante a solicitação GET no controlador) e os formulários:
<form:form method="POST" modelAttribute="userForm">
Você também deve especificar o caminho para ligar as propriedades userForm:
<form:input type="text" path="username" placeholder="Username"></form:input>
login.jsp Página de
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>
Esta página, como já mencionado, é tratada pelo controlador Spring por padrão. É importante especificar a ação:
action = "/ login" e o nome da entrada.
página de
administração admin.jsp .

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 A página de notícias é estática. É usado apenas para demonstrar os direitos do usuário, portanto, o conteúdo de sua escolha.
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. Iniciando o aplicativo
Na classe principal Application, adicione o seguinte: @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Antes de prosseguir para a próxima etapa, verifique se a estrutura do seu projeto corresponde à apresentada no início.É hora de criar um banco de dados vazio chamado spring , você precisa fazer isso antes do primeiro aplicativo ser iniciado e apenas uma vez.Você pode executar o aplicativo e ver como o banco de dados é alterado - 3 tabelas vazias serão criadas nele. Você precisa adicionar funções de usuário à tabela t_role:Consulta SQL adicionando funções INSERT INTO public.t_role(id, name) VALUES (1, 'ROLE_USER'), (2, 'ROLE_ADMIN');
Agora você pode tentar se registrar. O aplicativo não fornece um método para registrar um usuário administrador, mas é necessário para demonstração. Portanto, depois de registrar um novo usuário, adicione uma entrada à tabela de funções do usuário que fornece esta função:Consulta SQL adicionando função de administrador INSERT INTO public.t_user_roles(user_id, roles_id) VALUES (1, 2);
Se, após adicionar direitos de administrador, você não puder acessar a página do administrador (erro 403), acesse o site. Somente o usuário com a função de administrador tem acessoà página http: // localhost: 8080 / admin . http: // localhost: 8080 / news que qualquer usuário registrado verá. Você também pode tentar acessar as páginas de registro e login, sendo autorizado no site.Conclusão
Como resultado, foi criada uma aplicação web na qual podemos controlar o acesso do usuário às páginas do site usando funções. Você pode atribuir várias funções a um usuário. Por exemplo, ao registrar um novo usuário, adicionamos a função Usuário, que é básica para todos, e, ao solicitar privilégios adicionais pelo usuário, podemos atribuir a ele a função Escritor, que permitirá adicionar novas notícias ao site.Os arquivos css e js foram criados, mas seu conteúdo não foi apresentado. Se desejar, você pode adicionar design, por exemplo, usando o Bootstrap e interatividade usando js.Faça o download do projeto finalizado.Fontes utilizadas
- Registro e login com Spring Boot, Spring Security, Spring Data JPA, Hibernate, MySQL, JSP, Bootstrap e Docker Compose
- O outro lado da primavera
- Revisão técnica Spring Security / Spring Security
- Spring
- : Spring 3 MVC + Spring Security + Hibernate