diff --git a/docs/advanced/spring-security-login-authentication-process.md b/docs/advanced/spring-security-login-authentication-process.md
new file mode 100644
index 0000000..89d0328
--- /dev/null
+++ b/docs/advanced/spring-security-login-authentication-process.md
@@ -0,0 +1,196 @@
+Spring Security的登录主要是由一系列的过滤器组成,我们如果需要修改登录的校验逻辑,只需要在过滤器链路上添加修改相关的逻辑即可。这里主要通过Spring Security的源码来了解相关的认证登录的逻辑。
+
+#### 1.Spring Security的认证流程
+
+主要分析:
+
+1. 认证用户的流程
+2. 如何进行认证校验
+3. 认证成功后怎么获取用户信息
+
+具体的过滤器链路如下所示:
+
+[](https://imgtu.com/i/cT2G4g)
+
+Spring Security的认证流程图如下,认证的主要过程有:
+
+1. 用户提交用户名和密码,然后通过UsernamePasswordAuthenticationFilter对其进行封装成为UsernamePasswordAuthenticationToken对象,这个是AbstractAuthenticationToken的子类,而AbstractAuthenticationToken又是Authentication的一个实现,所以可以看到后续获取的都是Authentication类型的对象实例;
+2. 将第一步的UsernamePasswordAuthenticationToken对象传递给AuthenticationManager;
+3. 通过AbstractUserDetailsAuthenticationProvider的默认实现类DaoAuthenticationProvider的retrieveUser方法,这个方法会调用UserDetailsService的loadUserByUsername方法来进行用户名和密码的判断,使用的默认的逻辑进行处理;
+4. 将成功认证后的用户信息放入到SecurityContextHolder中,之后可以通过SecurityContext获取用户的相关信息。
+
+[](https://imgtu.com/i/coGpvR)
+
+spring-security源码下载地址:
+
+```java
+https://github.com/spring-projects/spring-security
+```
+
+#### 2.Spring Security的认证源码分析
+
+##### 2.1 搭建项目并访问
+
+首先我们搭建一个Spring Security的项目,使用Spring Boot可以很方便的进行集成开发,主要引入如下的依赖即可(当然也可以查看官网,选择合适的版本):
+
+```java
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+```
+
+启动项目后会随机生成一个密码串,这里需要复制保存以便登录的时候使用:
+
+[](https://imgtu.com/i/coJ0ld)
+
+访问登录地址:
+
+```java
+http://localhost:8080/login
+```
+
+[](https://imgtu.com/i/coJfpQ)
+
+默认的账户名和密码:
+
+```java
+账户名: user
+密码: 项目启动时生成的密码串
+```
+
+##### 2.2 进行源码分析
+
+1. 进行断点后会发现首先进入的是UsernamePasswordAuthenticationFilter的attemptAuthentication(HttpServletRequest request, HttpServletResponse response)方法,会对用户名和密码进行封装成UsernamePasswordAuthenticationToken对象,然后调用this.getAuthenticationManager().authenticate(authRequest)方法进入到AuthenticationManager中。
+
+ attemptAuthentication方法源码如下所示:
+
+```java
+@Override
+ public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
+ throws AuthenticationException {
+ if (this.postOnly && !request.getMethod().equals("POST")) {
+ throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
+ }
+ String username = obtainUsername(request);
+ username = (username != null) ? username : "";
+ username = username.trim();
+ String password = obtainPassword(request);
+ password = (password != null) ? password : "";
+ UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
+ // Allow subclasses to set the "details" property
+ setDetails(request, authRequest);
+ return this.getAuthenticationManager().authenticate(authRequest);
+ }
+```
+
+2. 随后请求进入到WebSecurityConfigurerAdapter的AuthenticationManagerDelegator中,AuthenticationManagerDelegator是AuthenticationManager的一个子类,最后封装成为UsernamePasswordAuthenticationToken对象,供DaoAuthenticationProvider使用。
+
+ AuthenticationManagerDelegator的源码如下:
+
+ ```java
+ static final class AuthenticationManagerDelegator implements AuthenticationManager {
+ private AuthenticationManagerBuilder delegateBuilder;
+ private AuthenticationManager delegate;
+ private final Object delegateMonitor = new Object();
+ private Set beanNames;
+
+ AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder, ApplicationContext context) {
+ Assert.notNull(delegateBuilder, "delegateBuilder cannot be null");
+ Field parentAuthMgrField = ReflectionUtils.findField(AuthenticationManagerBuilder.class, "parentAuthenticationManager");
+ ReflectionUtils.makeAccessible(parentAuthMgrField);
+ this.beanNames = getAuthenticationManagerBeanNames(context);
+ validateBeanCycle(ReflectionUtils.getField(parentAuthMgrField, delegateBuilder), this.beanNames);
+ this.delegateBuilder = delegateBuilder;
+ }
+
+ public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+ if (this.delegate != null) {
+ return this.delegate.authenticate(authentication);
+ } else {
+ synchronized(this.delegateMonitor) {
+ if (this.delegate == null) {
+ this.delegate = (AuthenticationManager)this.delegateBuilder.getObject();
+ this.delegateBuilder = null;
+ }
+ }
+
+ return this.delegate.authenticate(authentication);
+ }
+ }
+
+ private static Set getAuthenticationManagerBeanNames(ApplicationContext applicationContext) {
+ String[] beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, AuthenticationManager.class);
+ return new HashSet(Arrays.asList(beanNamesForType));
+ }
+
+ private static void validateBeanCycle(Object auth, Set beanNames) {
+ if (auth != null && !beanNames.isEmpty() && auth instanceof Advised) {
+ TargetSource targetSource = ((Advised)auth).getTargetSource();
+ if (targetSource instanceof LazyInitTargetSource) {
+ LazyInitTargetSource lits = (LazyInitTargetSource)targetSource;
+ if (beanNames.contains(lits.getTargetBeanName())) {
+ throw new FatalBeanException("A dependency cycle was detected when trying to resolve the AuthenticationManager. Please ensure you have configured authentication.");
+ }
+ }
+ }
+ }
+ }
+ ```
+
+ org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration.AuthenticationManagerDelegator#authenticate
+
+ ```java
+ @Override
+ public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+ if (this.delegate != null) {
+ return this.delegate.authenticate(authentication);
+ }
+ synchronized (this.delegateMonitor) {
+ if (this.delegate == null) {
+ this.delegate = this.delegateBuilder.getObject();
+ this.delegateBuilder = null;
+ }
+ }
+ return this.delegate.authenticate(authentication);
+ }
+ ```
+
+3. 进入到DaoAuthenticationProvider的retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)方法进行用户的认证,这里的认证主要会调用默认的UserDetailsService对用户名和密码进行校验,如果是使用的类似于Mysql的数据源,其默认的实现是JdbcDaoImpl。
+
+ org.springframework.security.authentication.dao.DaoAuthenticationProvider#retrieveUser
+
+ ```java
+ @Override
+ protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
+ throws AuthenticationException {
+ prepareTimingAttackProtection();
+ try {
+ UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
+ if (loadedUser == null) {
+ throw new InternalAuthenticationServiceException(
+ "UserDetailsService returned null, which is an interface contract violation");
+ }
+ return loadedUser;
+ }
+ catch (UsernameNotFoundException ex) {
+ mitigateAgainstTimingAttack(authentication);
+ throw ex;
+ }
+ catch (InternalAuthenticationServiceException ex) {
+ throw ex;
+ }
+ catch (Exception ex) {
+ throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
+ }
+ }
+
+ ```
+
+4. 将上一步认证后的用户实例放入SecurityContextHolder中,至此我们可以很方便的从SecurityContextHolder中获取用户信息,方法如下:
+
+ ```java
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ ```
+
+
diff --git a/docs/basis/PowerMockRunnerAndMockito.md b/docs/basis/PowerMockRunnerAndMockito.md
new file mode 100644
index 0000000..d5a7b12
--- /dev/null
+++ b/docs/basis/PowerMockRunnerAndMockito.md
@@ -0,0 +1,177 @@
+单元测试可以提高测试开发的效率,减少代码错误率,提高代码健壮性,提高代码质量。在Spring框架中常用的两种测试框架:PowerMockRunner和SpringRunner两个单元测试,鉴于SpringRunner启动的一系列依赖和数据连接的问题,推荐使用PowerMockRunner,这样能有效的提高测试的效率,并且其提供的API能覆盖的场景广泛,使用方便,可谓是Java单元测试之模拟利器。
+
+#### 1. PowerMock是什么?
+
+PowerMock是一个Java模拟框架,可用于解决通常认为很难甚至无法测试的测试问题。使用PowerMock,可以模拟静态方法,删除静态初始化程序,允许模拟而不依赖于注入,等等。PowerMock通过在执行测试时在运行时修改字节码来完成这些技巧。PowerMock还包含一些实用程序,可让您更轻松地访问对象的内部状态。
+
+
+举个例子,你在使用Junit进行单元测试时,并不想让测试数据进入数据库,怎么办?这个时候就可以使用PowerMock,拦截数据库操作,并模拟返回参数。
+
+#### 2. PowerMock包引入
+
+```xml
+
+
+ org.powermock
+ powermock-core
+ 2.0.2
+ test
+
+
+org.mockito
+mockito-core
+2.23.0
+
+
+org.powermock
+powermock-module-junit4
+2.0.4
+test
+
+
+org.powermock
+powermock-api-mockito2
+2.0.2
+test
+
+
+com.github.jsonzou
+jmockdata
+4.3.0
+
+
+```
+
+#### 3. 重要注解说明
+
+```java
+@RunWith(PowerMockRunner.class) // 告诉JUnit使用PowerMockRunner进行测试
+@PrepareForTest({RandomUtil.class}) // 所有需要测试的类列在此处,适用于模拟final类或有final, private, static, native方法的类
+@PowerMockIgnore("javax.management.*") //为了解决使用powermock后,提示classloader错误
+```
+
+
+
+#### 4. 使用示例
+
+##### 4.1 模拟接口返回
+
+首先对接口进行mock,然后录制相关行为
+
+```java
+InterfaceToMock mock = Powermockito.mock(InterfaceToMock.class)
+
+Powermockito.when(mock.method(Params…)).thenReturn(value)
+
+Powermockito.when(mock.method(Params..)).thenThrow(Exception)
+```
+
+##### 4.2 设置对象的private属性
+
+需要使用whitebox向class或者对象中赋值。
+
+如我们已经对接口尽心了mock,现在需要将此mock加入到对象中,可以采用如下方法:
+
+```java
+Whitebox.setInternalState(Object object, String fieldname, Object… value);
+```
+
+其中object为需要设置属性的静态类或对象。
+
+##### 4.3 模拟构造函数
+
+对于模拟构造函数,也即当出现new InstanceClass()时可以将此构造函数拦截并替换结果为我们需要的mock对象。
+
+注意:使用时需要加入标记:
+
+```java
+@RunWith(PowerMockRunner.class)
+
+@PrepareForTest({ InstanceClass.class })
+
+@PowerMockIgnore("javax.management.\*")
+
+Powermockito.whenNew(InstanceClass.class).thenReturn(Object value)
+```
+
+##### 4.4 模拟静态方法
+
+模拟静态方法类似于模拟构造函数,也需要加入注释标记。
+
+```java
+@RunWith(PowerMockRunner.class)
+
+@PrepareForTest({ StaticClassToMock.class })
+
+@PowerMockIgnore("javax.management.\*")
+
+Powermockito.mockStatic(StaticClassToMock.class);
+
+ Powermockito.when(StaticClassToMock.method(Object.. params)).thenReturn(Object value)
+```
+
+##### 4.5 模拟final方法
+
+Final方法的模拟类似于模拟静态方法。
+
+```java
+@RunWith(PowerMockRunner.class)
+
+@PrepareForTest({ FinalClassToMock.class })
+
+@PowerMockIgnore("javax.management.\*")
+
+Powermockito.mockStatic(FinalClassToMock.class);
+
+ Powermockito.when(StaticClassToMock.method(Object.. params)).thenReturn(Object value)
+```
+
+##### 4.6 模拟静态类
+
+模拟静态类类似于模拟静态方法。
+
+##### 4.7 使用spy方法避免执行被测类中的成员函数
+
+如被测试类为:TargetClass,想要屏蔽的方法为targetMethod.
+
+```java
+1) PowerMockito.spy(TargetClass.class);
+
+2) Powemockito.when(TargetClass.targetMethod()).doReturn()
+
+3) 注意加入
+
+@RunWith(PowerMockRunner.class)
+
+@PrepareForTest(DisplayMoRelationBuilder.class)
+
+@PowerMockIgnore("javax.management.*")
+```
+
+##### 4.8 参数匹配器
+
+有时我们在处理doMethod(Param param)时,不想进行精确匹配,这时可以使用Mockito提供的模糊匹配方式。
+
+如:Mockito.anyInt(),Mockito.anyString()
+
+##### 4.9 处理public void型的静态方法
+
+```java
+Powermockito.doNothing.when(T class2mock, String method, … params>
+```
+
+#### 5. 单元测试用例可选清单
+
+输入数据验证:这些检查通常可以对输入到应用程序系统中的数据采用。
+
+- 必传项测试
+- 唯一字段值测试
+- 空值测试
+- 字段只接受允许的字符
+- 负值测试
+- 字段限于字段长度规范
+- 不可能的值
+- 垃圾值测试
+- 检查字段之间的依赖性
+- 等效类划分和边界条件测试
+- 错误和异常处理测试
\ No newline at end of file