mirror of
https://github.com/OtusTeam/Spring.git
synced 2026-06-20 11:14:34 +00:00
Примеры к занятию по авторизации
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
<?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>ru.otus</groupId>
|
||||
<artifactId>spring-framework-26-acl</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.6.10</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<ehcache-core.version>2.6.11</ehcache-core.version>
|
||||
<swagger.version>3.0.0</swagger.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>11</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<!-- Spring Security ACL и зависимости-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-acl</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache-core</artifactId>
|
||||
<version>${ehcache-core.version}</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
|
||||
<!-- <version>1.4.198</version>-->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-ui</artifactId>
|
||||
<version>1.6.9</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,14 @@
|
||||
package ru.otus.spring;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
|
||||
@SpringBootApplication
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Main.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package ru.otus.spring.model;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "system_message")
|
||||
public class NoticeMessage {
|
||||
|
||||
@Id
|
||||
@Column
|
||||
private Integer id;
|
||||
@Column
|
||||
private String content;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package ru.otus.spring.model;
|
||||
|
||||
public class Pack {
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package ru.otus.spring.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.security.access.prepost.PostAuthorize;
|
||||
import org.springframework.security.access.prepost.PostFilter;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import ru.otus.spring.model.NoticeMessage;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface NoticeMessageRepository extends JpaRepository<NoticeMessage, Integer> {
|
||||
|
||||
@PostFilter("hasPermission(filterObject, 'READ')")
|
||||
List<NoticeMessage> findAll();
|
||||
|
||||
@PostAuthorize("hasPermission(returnObject, 'READ')")
|
||||
NoticeMessage getById(Integer id);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@PreAuthorize("hasPermission(#noticeMessage, 'WRITE')")
|
||||
NoticeMessage save(@Param("noticeMessage") NoticeMessage noticeMessage);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package ru.otus.spring.rest;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import ru.otus.spring.model.NoticeMessage;
|
||||
import ru.otus.spring.repository.NoticeMessageRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
public class NoticeMessageController {
|
||||
|
||||
private final NoticeMessageRepository repository;
|
||||
|
||||
public NoticeMessageController(NoticeMessageRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@GetMapping("/message")
|
||||
public List<NoticeMessage> getAll() {
|
||||
return repository.findAll();
|
||||
}
|
||||
|
||||
@GetMapping("/message/{id}")
|
||||
public NoticeMessage getById(@PathVariable("id") Integer id) {
|
||||
return repository.getById(id);
|
||||
}
|
||||
|
||||
@PutMapping("/message")
|
||||
public NoticeMessage getById(NoticeMessage message) {
|
||||
return repository.save(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package ru.otus.spring.security;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.ehcache.EhCacheFactoryBean;
|
||||
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
|
||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||
import org.springframework.security.acls.AclPermissionCacheOptimizer;
|
||||
import org.springframework.security.acls.AclPermissionEvaluator;
|
||||
import org.springframework.security.acls.domain.*;
|
||||
import org.springframework.security.acls.jdbc.BasicLookupStrategy;
|
||||
import org.springframework.security.acls.jdbc.JdbcMutableAclService;
|
||||
import org.springframework.security.acls.jdbc.LookupStrategy;
|
||||
import org.springframework.security.acls.model.PermissionGrantingStrategy;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Objects;
|
||||
|
||||
@Configuration
|
||||
public class AclConfig {
|
||||
|
||||
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
@Bean
|
||||
public EhCacheBasedAclCache aclCache() {
|
||||
return new EhCacheBasedAclCache(
|
||||
Objects.requireNonNull(aclEhCacheFactoryBean().getObject()),
|
||||
permissionGrantingStrategy(),
|
||||
aclAuthorizationStrategy()
|
||||
);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public EhCacheFactoryBean aclEhCacheFactoryBean() {
|
||||
EhCacheFactoryBean ehCacheFactoryBean = new EhCacheFactoryBean();
|
||||
ehCacheFactoryBean.setCacheManager(aclCacheManager().getObject());
|
||||
ehCacheFactoryBean.setCacheName("aclCache");
|
||||
return ehCacheFactoryBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public EhCacheManagerFactoryBean aclCacheManager() {
|
||||
return new EhCacheManagerFactoryBean();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PermissionGrantingStrategy permissionGrantingStrategy() {
|
||||
return new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AclAuthorizationStrategy aclAuthorizationStrategy() {
|
||||
return new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_EDITOR"));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler() {
|
||||
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
AclPermissionEvaluator permissionEvaluator = new AclPermissionEvaluator(aclService());
|
||||
expressionHandler.setPermissionEvaluator(permissionEvaluator);
|
||||
expressionHandler.setPermissionCacheOptimizer(new AclPermissionCacheOptimizer(aclService()));
|
||||
return expressionHandler;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LookupStrategy lookupStrategy() {
|
||||
return new BasicLookupStrategy(dataSource, aclCache(), aclAuthorizationStrategy(), new ConsoleAuditLogger());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JdbcMutableAclService aclService() {
|
||||
return new JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package ru.otus.spring.security;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
|
||||
|
||||
@Configuration
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
|
||||
public class AclMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
|
||||
|
||||
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
|
||||
@Autowired
|
||||
MethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler;
|
||||
|
||||
@Override
|
||||
protected MethodSecurityExpressionHandler createExpressionHandler() {
|
||||
return defaultMethodSecurityExpressionHandler;
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package ru.otus.spring.security;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfiguration {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain( HttpSecurity http ) throws Exception {
|
||||
http
|
||||
.csrf().disable()
|
||||
.authorizeHttpRequests( ( authorize ) -> authorize
|
||||
.antMatchers( "/**", "/" ).permitAll()
|
||||
)
|
||||
.formLogin();
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public InMemoryUserDetailsManager userDetailsService() {
|
||||
var users = new ArrayList<UserDetails>();
|
||||
users.add( User
|
||||
.withDefaultPasswordEncoder().username( "admin" ).password( "password" ).roles( "EDITOR" )
|
||||
.build() );
|
||||
users.add( User
|
||||
.withDefaultPasswordEncoder().username( "user" ).password( "password" ).roles( "USER" )
|
||||
.build() );
|
||||
users.add( User
|
||||
.withDefaultPasswordEncoder().username( "someone" ).password( "password" ).roles( "SOMEONE" )
|
||||
.build() );
|
||||
return new InMemoryUserDetailsManager( users );
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package ru.otus.spring.service;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.domain.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.domain.PrincipalSid;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.MutableAclService;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.otus.spring.model.NoticeMessage;
|
||||
import ru.otus.spring.repository.NoticeMessageRepository;
|
||||
|
||||
@Service
|
||||
public class NoticeService {
|
||||
@Autowired
|
||||
protected MutableAclService mutableAclService;
|
||||
|
||||
@Autowired
|
||||
private NoticeMessageRepository repository;
|
||||
|
||||
public void add( NoticeMessage noticeMessage ) {
|
||||
repository.save( noticeMessage );
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
final Sid owner = new PrincipalSid( authentication );
|
||||
ObjectIdentity oid = new ObjectIdentityImpl( noticeMessage.getClass(), noticeMessage.getId() );
|
||||
|
||||
final Sid admin = new GrantedAuthoritySid("ROLE_EDITOR");
|
||||
|
||||
MutableAcl acl = mutableAclService.createAcl( oid );
|
||||
acl.setOwner( owner );
|
||||
acl.insertAce( acl.getEntries().size(), BasePermission.ADMINISTRATION, admin, true );
|
||||
|
||||
mutableAclService.updateAcl( acl );
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
spring:
|
||||
h2:
|
||||
console:
|
||||
enabled: true
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: none
|
||||
datasource:
|
||||
url: jdbc:h2:mem:testdb
|
||||
|
||||
springdoc:
|
||||
packages-to-scan: ru.otus.spring.rest
|
||||
paths-to-match: /**
|
||||
@@ -0,0 +1,28 @@
|
||||
INSERT INTO system_message(id,content) VALUES
|
||||
(1,'First Level Message'),
|
||||
(2,'Second Level Message'),
|
||||
(3,'Third Level Message');
|
||||
|
||||
|
||||
INSERT INTO acl_sid (id, principal, sid) VALUES
|
||||
(1, 1, 'admin'),
|
||||
(2, 1, 'user'),
|
||||
(3, 0, 'ROLE_EDITOR');
|
||||
|
||||
INSERT INTO acl_class (id, class) VALUES
|
||||
(1, 'ru.otus.spring.model.NoticeMessage');
|
||||
|
||||
INSERT INTO acl_object_identity (id, object_id_class, object_id_identity, parent_object, owner_sid, entries_inheriting) VALUES
|
||||
(1, 1, 1, NULL, 3, 0),
|
||||
(2, 1, 2, NULL, 3, 0),
|
||||
(3, 1, 3, NULL, 3, 0);
|
||||
|
||||
INSERT INTO acl_entry (id, acl_object_identity, ace_order, sid, mask,
|
||||
granting, audit_success, audit_failure) VALUES
|
||||
(1, 1, 1, 1, 1, 1, 1, 1),
|
||||
(2, 1, 2, 1, 2, 1, 1, 1),
|
||||
(3, 1, 3, 3, 1, 1, 1, 1),
|
||||
(4, 2, 1, 2, 1, 1, 1, 1),
|
||||
(5, 2, 2, 3, 1, 1, 1, 1),
|
||||
(6, 3, 1, 3, 1, 1, 1, 1),
|
||||
(7, 3, 2, 3, 2, 1, 1, 1);
|
||||
@@ -0,0 +1,58 @@
|
||||
create table IF NOT EXISTS system_message (id integer not null, content varchar(255), primary key (id));
|
||||
|
||||
CREATE TABLE IF NOT EXISTS acl_sid (
|
||||
id bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
principal tinyint(1) NOT NULL,
|
||||
sid varchar(100) NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY unique_uk_1 (sid,principal)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS acl_class (
|
||||
id bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
class varchar(255) NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY unique_uk_2 (class)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS acl_entry (
|
||||
id bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
acl_object_identity bigint(20) NOT NULL,
|
||||
ace_order int(11) NOT NULL,
|
||||
sid bigint(20) NOT NULL,
|
||||
mask int(11) NOT NULL,
|
||||
granting tinyint(1) NOT NULL,
|
||||
audit_success tinyint(1) NOT NULL,
|
||||
audit_failure tinyint(1) NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY unique_uk_4 (acl_object_identity,ace_order)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS acl_object_identity (
|
||||
id bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
object_id_class bigint(20) NOT NULL,
|
||||
object_id_identity bigint(20) NOT NULL,
|
||||
parent_object bigint(20) DEFAULT NULL,
|
||||
owner_sid bigint(20) DEFAULT NULL,
|
||||
entries_inheriting tinyint(1) NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY unique_uk_3 (object_id_class,object_id_identity)
|
||||
);
|
||||
|
||||
ALTER TABLE acl_entry
|
||||
ADD FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity(id);
|
||||
|
||||
ALTER TABLE acl_entry
|
||||
ADD FOREIGN KEY (sid) REFERENCES acl_sid(id);
|
||||
|
||||
--
|
||||
-- Constraints for table acl_object_identity
|
||||
--
|
||||
ALTER TABLE acl_object_identity
|
||||
ADD FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id);
|
||||
|
||||
ALTER TABLE acl_object_identity
|
||||
ADD FOREIGN KEY (object_id_class) REFERENCES acl_class (id);
|
||||
|
||||
ALTER TABLE acl_object_identity
|
||||
ADD FOREIGN KEY (owner_sid) REFERENCES acl_sid (id);
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
Вам доступ запрещён!
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
<a th:href="@{login}">login</a>
|
||||
<br>
|
||||
<a th:href="@{logout}">logout</a>
|
||||
<br>
|
||||
<a th:href="@{h2-console}">h2-console</a>
|
||||
<br>
|
||||
<a th:href="@{swagger-ui.html}">/swagger</a>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,54 @@
|
||||
<?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>ru.otus</groupId>
|
||||
<artifactId>classwork</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.7.8</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package ru.otus.spring;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SpringSecurityAuthorization {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringSecurityAuthorization.class);
|
||||
}
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package ru.otus.spring.controller;
|
||||
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import ru.otus.spring.service.MyService;
|
||||
|
||||
@Controller
|
||||
public class PagesController {
|
||||
|
||||
private final MyService myService;
|
||||
|
||||
public PagesController(MyService myService) {
|
||||
this.myService = myService;
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public String indexPage() {
|
||||
return "index";
|
||||
}
|
||||
|
||||
@GetMapping("/public")
|
||||
public String publicPage() {
|
||||
return "public";
|
||||
}
|
||||
|
||||
@GetMapping("/user")
|
||||
public String userPage() {
|
||||
myService.onlyUser();
|
||||
return "user";
|
||||
}
|
||||
|
||||
@GetMapping("/manager")
|
||||
public String managerPage() {
|
||||
return "manager";
|
||||
}
|
||||
|
||||
@GetMapping("/admin")
|
||||
//@Secured( "ADMIN" )
|
||||
public String adminPage() {
|
||||
myService.onlyUser();
|
||||
//myService.onlyAdmin();
|
||||
return "admin";
|
||||
}
|
||||
|
||||
@GetMapping("/authenticated")
|
||||
public String authenticatedPage() {
|
||||
UserDetails userDetails = (UserDetails) SecurityContextHolder
|
||||
.getContext().getAuthentication().getPrincipal();
|
||||
System.out.println(userDetails.getUsername());
|
||||
return "authenticated";
|
||||
}
|
||||
|
||||
@GetMapping("/success")
|
||||
public String successPage() {
|
||||
return "success";
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package ru.otus.spring.controller;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@ControllerAdvice
|
||||
public class SecurityControllerAdvice {
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public ResponseEntity<String> accessError() {
|
||||
return ResponseEntity.of(Optional.of("Неудачник"));
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package ru.otus.spring.security;
|
||||
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
|
||||
@EnableGlobalMethodSecurity(
|
||||
securedEnabled = true,
|
||||
prePostEnabled = true
|
||||
)
|
||||
public class MethodSecurityConfiguration {
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package ru.otus.spring.security;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfiguration {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain( HttpSecurity http ) throws Exception {
|
||||
http
|
||||
.csrf().disable()
|
||||
.authorizeHttpRequests( ( authorize ) -> authorize
|
||||
.antMatchers( "/public", "/" ).permitAll()
|
||||
.antMatchers( "/authenticated", "/success" ).authenticated()
|
||||
.antMatchers( "/manager" ).hasAnyRole( "MANAGER" )
|
||||
.antMatchers( "/user" ).hasAnyRole( "ADMIN", "USER" )
|
||||
.anyRequest().denyAll()
|
||||
)
|
||||
.formLogin()
|
||||
|
||||
;
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public InMemoryUserDetailsManager userDetailsService() {
|
||||
var users = new ArrayList<UserDetails>();
|
||||
users.add( User
|
||||
.withDefaultPasswordEncoder().username( "admin" ).password( "password" ).roles( "ADMIN" )
|
||||
.build() );
|
||||
users.add( User
|
||||
.withDefaultPasswordEncoder().username( "user" ).password( "password" ).roles( "USER" )
|
||||
.build() );
|
||||
return new InMemoryUserDetailsManager( users );
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package ru.otus.spring.service;
|
||||
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class MyService {
|
||||
@PreAuthorize("hasRole('ROLE_USER') && {new java.util.Random().nextInt()%2 == 0}")
|
||||
public String onlyUser() {
|
||||
return "My love";
|
||||
}
|
||||
|
||||
@Secured("ADMIN")
|
||||
public void onlyAdmin() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
Страница с доступом только админу
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
Только для аторизованных
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
Вам доступ запрещён!
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
<a th:href="@{public}">/public</a>
|
||||
<br>
|
||||
<a th:href="@{authenticated}">/authenticated</a>
|
||||
<br>
|
||||
<a th:href="@{user}">/user</a>
|
||||
<br>
|
||||
<a th:href="@{admin}">/admin</a>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
Доступ к MANAGER
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
Доступен всем
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
Вы успешно вошли !
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
Доступ к USER
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,54 @@
|
||||
<?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>ru.otus</groupId>
|
||||
<artifactId>solution2</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.7.8</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package ru.otus.spring;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SpringSecurityAuthorization {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringSecurityAuthorization.class);
|
||||
}
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package ru.otus.spring.controller;
|
||||
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import ru.otus.spring.service.MyService;
|
||||
|
||||
@Controller
|
||||
public class PagesController {
|
||||
|
||||
private final MyService myService;
|
||||
|
||||
public PagesController(MyService myService) {
|
||||
this.myService = myService;
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public String indexPage() {
|
||||
return "index";
|
||||
}
|
||||
|
||||
@GetMapping("/public")
|
||||
public String publicPage() {
|
||||
return "public";
|
||||
}
|
||||
|
||||
@GetMapping("/user")
|
||||
public String userPage() {
|
||||
return "user";
|
||||
}
|
||||
|
||||
@GetMapping("/manager")
|
||||
public String managerPage() {
|
||||
myService.onlyAdmin();
|
||||
return "manager";
|
||||
}
|
||||
|
||||
@GetMapping("/admin")
|
||||
public String adminPage() {
|
||||
return "admin";
|
||||
}
|
||||
|
||||
@GetMapping("/authenticated")
|
||||
public String authenticatedPage() {
|
||||
UserDetails userDetails = (UserDetails) SecurityContextHolder
|
||||
.getContext().getAuthentication().getPrincipal();
|
||||
System.out.println(userDetails.getUsername());
|
||||
return "authenticated";
|
||||
}
|
||||
|
||||
@GetMapping("/success")
|
||||
public String successPage() {
|
||||
return "success";
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package ru.otus.spring.security;
|
||||
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public class MethodSecurityConfiguration {
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package ru.otus.spring.security;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfiguration {
|
||||
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain( HttpSecurity http ) throws Exception {
|
||||
http
|
||||
.csrf().disable()
|
||||
// .sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS)
|
||||
// .and()
|
||||
.authorizeHttpRequests( ( authorize ) -> authorize
|
||||
.antMatchers( "/public", "/" ).permitAll()
|
||||
.antMatchers( "/authenticated", "/success" ).authenticated()
|
||||
.antMatchers( "/manager" ).hasAnyRole( "MANAGER" )
|
||||
.antMatchers( "/user" ).hasAnyRole( "ADMIN", "USER" )
|
||||
.anyRequest().denyAll()
|
||||
)
|
||||
.formLogin()
|
||||
|
||||
;
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public InMemoryUserDetailsManager userDetailsService() {
|
||||
var users = new ArrayList<UserDetails>();
|
||||
users.add( User
|
||||
.withDefaultPasswordEncoder().username( "admin" ).password( "password" ).roles( "ADMIN" )
|
||||
.build() );
|
||||
users.add( User
|
||||
.withDefaultPasswordEncoder().username( "user" ).password( "password" ).roles( "USER" )
|
||||
.build() );
|
||||
users.add( User
|
||||
.withDefaultPasswordEncoder().username( "manager" ).password( "password" ).roles( "MANAGER", "USER" )
|
||||
.build() );
|
||||
return new InMemoryUserDetailsManager( users );
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package ru.otus.spring.service;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class MyService {
|
||||
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public void onlyAdmin() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
Страница с доступом только админу
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
Только для аторизованных
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
Вам доступ запрещён!
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
<a th:href="@{public}">/public</a>
|
||||
<br>
|
||||
<a th:href="@{authenticated}">/authenticated</a>
|
||||
<br>
|
||||
<a th:href="@{user}">/user</a>
|
||||
<br>
|
||||
<a th:href="@{manager}">/manager</a>
|
||||
<br>
|
||||
<a th:href="@{admin}">/admin</a>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
Доступ к MANAGER
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
Доступен всем
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
Вы успешно вошли !
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
</head>
|
||||
<body>
|
||||
Доступ к USER
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user