DelegatingFilterProxy -> 代理 SpringSecurityFilterChain(FilterChainProxy) -> 安全认证链 AuthenticationFilter -> AuthenticationManager -> 配置认证用户信息 AuthenticationProvider -> 提供endpoint,如/oauth/authorize UserDetails -> AuthenticationToken -> SecurityContextHolder
- 自定义登陆过滤器 AbstractAuthenticationProcessingFilter
- 自定义登陆provider AuthenticationProvider
OAuth2 server = Security + AuthorizationEndpoint + TokenEndpoint resource server = OAuth2AuthenticationPrrocessingFilter:加载Authentication
@EnableAuthorizationServer -> ClientDetailsServiceConfigurer AuthorizationServerSecurityConfigurer AuthorizationServerEndpointConfigurer
- 注解:
@Configuration
@EnableAuthorizationServer
- 三个configurer
- ClientDetailsServiceConfigurer: 配置自定义的clientDetailsService等 clientDetailsService类主要是用来获取客户端信息, 包括客户端ID、客户端secret、授权类型等数据, 在使用时可以自定义clientDetailsService类(继承clientDetailsService), 然后在ClientDetailsServiceConfigurer中使用withClientDetails()使用自定义的clientDetailsService;
- AuthorizationServerSecurityConfigurer: 在endpoint上加一下限制,比如允许表单验证等
- AuthorizationServerEndpointsConfigurer: 配置endpoint以及tokenService等(包含授权类型service的使用) 自定义tokenService:
- 自定义Provider
Provider负责暴露OAuth2的
- SecurityFilters
create table users( username varchar_ignorecase(50) not null primary key, password varchar_ignorecase(50) not null, enabled boolean not null );
create table authorities ( username varchar_ignorecase(50) not null, authority varchar_ignorecase(50) not null, constraint fk_authorities_users foreign key(username) references users(username) );
create table groups ( id bigint generated by default as identity(start with 0) primary key, group_name varchar_ignorecase(50) not null );
create table group_authorities ( group_id bigint not null, authority varchar(50) not null, constraint fk_group_authorities_group foreign key(group_id) references groups(id) );
create table group_members ( id bigint generated by default as identity(start with 0) primary key, username varchar(50) not null, group_id bigint not null, constraint fk_group_members_group foreign key(group_id) references groups(id) );
create table persistent_logins ( username varchar(64) not null, series varchar(64) primary key, token varchar(64) not null, last_used timestamp not null );
CREATE TABLE acl_sid ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, principal BOOLEAN NOT NULL, sid VARCHAR(100) NOT NULL, UNIQUE KEY unique_acl_sid (sid, principal) ) ENGINE=InnoDB;
CREATE TABLE acl_class ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, class VARCHAR(100) NOT NULL, UNIQUE KEY uk_acl_class (class) ) ENGINE=InnoDB;
CREATE TABLE acl_object_identity ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, object_id_class BIGINT UNSIGNED NOT NULL, object_id_identity VARCHAR(36) NOT NULL, parent_object BIGINT UNSIGNED, owner_sid BIGINT UNSIGNED, entries_inheriting BOOLEAN NOT NULL, UNIQUE KEY uk_acl_object_identity (object_id_class, object_id_identity), CONSTRAINT fk_acl_object_identity_parent FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id), CONSTRAINT fk_acl_object_identity_class FOREIGN KEY (object_id_class) REFERENCES acl_class (id), CONSTRAINT fk_acl_object_identity_owner FOREIGN KEY (owner_sid) REFERENCES acl_sid (id) ) ENGINE=InnoDB;
CREATE TABLE acl_entry ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, acl_object_identity BIGINT UNSIGNED NOT NULL, ace_order INTEGER NOT NULL, sid BIGINT UNSIGNED NOT NULL, mask INTEGER UNSIGNED NOT NULL, granting BOOLEAN NOT NULL, audit_success BOOLEAN NOT NULL, audit_failure BOOLEAN NOT NULL, UNIQUE KEY unique_acl_entry (acl_object_identity, ace_order), CONSTRAINT fk_acl_entry_object FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity (id), CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id) ) ENGINE=InnoDB;
// authorization_code
// code
http://localhost:9992/oas/oauth/authorize?client_id=admin&redirect_uri=http%3A%2F%2Flocalhost%3A9992%2Foas%2Flogin&response_type=code&state=cSTsdK
// code->token
http://localhost:9992/oas/oauth/token?client_id=admin&client_secret=123456&redirect_uri=http%3A%2F%2Flocalhost%3A9992%2Foas%2Flogin&grant_type=authorization_code&code=ugMZFY&state=ZGFelm
// implicit, 浏览器中访问
http://localhost:9992/oas/oauth/authorize?client_id=admin&redirect_uri=http%3A%2F%2Flocalhost%3A9992%2Foas%2Flogin&response_type=token
// password
http://localhost:9992/oas/oauth/token?username=test&password=test&client_id=admin&client_secret=123456&grant_type=password
// client_credentials
http://localhost:9992/oas/oauth/token?client_id=admin&client_secret=123456&grant_type=client_credentials
// refresh_token
http://localhost:9992/oas/oauth/token?client_id=admin&client_secret=123456&grant_type=refresh_token
设计模式大体可分为三类:
- 创建者模式(5种): 单例、工厂方法、抽象工厂、建造者、原型。
- 结构型模式(7种): 适配器、装饰器、代理、外观、桥接、组合、享元。
- 行为型模式(11种): 策略、模板、观察者、迭代子、责任链、命令、备忘录、状态、访问者、中介、解释器。
设计模式遵循的原则:
- 开闭原则
- 里氏代换原则
- 依赖倒转原则
- 接口隔离原则
- 迪米特法则(最少知道原则)
- 合成复用原则
在内部创建一个实例,构造器全部设置为private,所有的方法均在该实例上做改动,在创建时类的实例化只能执行一次,可以采用多种方法来实现,如Synchronized关键字,或者利用内部类等机制来实现。
public class Singleton {
private Singleton() {}
private static class SingletonBuild {
private static Singleton value = new Singleton();
}
public Stingleton getInstance() {
return SingletonBuild.value;
}
}
常用的工厂模式是静态工厂,利用static方法,作为一种类似于常见的工具类utils等辅助效果,一般情况下工厂类不需要实例化。
interface food{}
class A implements food{}
class B implements food{}
public class StaticFactory {
private StaticFactory() {}
public static food getA() {return new A();}
public static food getB() {return new B();}
}
一个基础接口定义了功能,每个实现接口的子类就是产品,然后定义一个工厂接口,实现了工厂接口就是工厂,这时候,接口编程的有点就出现了,我们可以新增产品类(只需要实现产品接口),只需要同时新增一个工厂类,客户端就可以轻松调出新产品的代码。
interface food {}
class A implements food {}
class B implements food {}
interface produce {
food get();
}
class FactoryForA implements produce {
@Override
public food get() {
return new A();
}
}
class FactoryForB implements produce {
@Override
public food get() {
return new B();
}
}
public class Builder {
static class Student {
String name = null;
String age = null;
String sex = null;
public Student(StudentBuilder builder) {
this.name = builder.name;
this.age = builder.age;
this.sex = builder.sex;
}
static class StudentBuilder {
String name = null;
String age = null;
String sex = null;
public Student build() {
return new Student(this);
}
public StudentBuilder setName(String name) {
this.name = name;
return this;
}
public StudentBuilder setAge(String age) {
this.age = age;
return this;
}
public StudentBuilder setSex(String sex) {
this.sex = sex;
return this;
}
}
}
}
用对象作为原型,使用clone()方法创建新的实例。
public class Protype implements Cloneable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() {
try {
return super.clone();
} catch(CloneNotSupportedException e) {
e.printStackTrace();
} finally{
return null; // ?
}
}
}
Spring的核心是IOC和DI,即控制反转和依赖注入, IOC指把对象的装配和管理交给spring容器 对象之间的关系Spring使用DI来维护
Spring容器 | ||
---|---|---|
A类的实例 | 注入 | B类的实例 |
Spring容器装配bean:ApplicationContext和BeanFactory
BeanFactory:getBean()装配 ---> ApplicationContext:容器初始化阶段对所有容器中的bean进行装配
IOC之基于注解的DI Bean的创建 @Component @Repository @Service @Controller Bean属性依赖注入 @Value: 基本类型, String等 @Autowired: 对象 @Resource: 对象 对于对象类型的注入, 分为两种byName和byType byName: @Autowired + @Qualifier或@Resource(name="") byType: @Autowired/@Qualifier/@Resource
AOP的实现原理 - JDK动态代理和CGLIB动态代理
JDK动代理需要目标对象实现接口,CGLIB动态代理则无需如此。
切面(切面代码) 目标对象(可以被切面增强的对象) 织入(把切面代码插入到目标对象方法的过程) 通知(前置/后置/环绕) 顾问 连接点(目标对象中完成主逻辑的方法,可以被切面织入的方法) 切入点(目标对象具体被切面织入的方法)
通知和顾问: MethodBeforeAdvice:前置 AfterReturningAdvice:后置 MethodInterceptor:环绕 NameMatchMethodPointcutAdvisor
- Aspect Oriented Programming with Spring 面向过程编程(AOP)通过
快捷键 Ctrl+R,替换文本 Ctrl+F,查找文本 Ctrl+N,可以快速打开类 Ctrl+F12,可以显示当前文件的结构 Ctrl+O,重写方法 Ctrl+Alt+Space,类名自动完成 Alt+F3,逐个往下查找相同文本,并高亮显示 Alt+F7,查找整个工程中使用地某一个类、方法或者变量的位置 Alt+F8,计算变量值 Ctrl+I,实现方法