diff --git a/35.Spring-Security-Authentication/pom.xml b/35.Spring-Security-Authentication/pom.xml
new file mode 100644
index 0000000..bfee0e1
--- /dev/null
+++ b/35.Spring-Security-Authentication/pom.xml
@@ -0,0 +1,58 @@
+
+
+ 4.0.0
+
+ cc.mrbird
+ Security
+ 1.0-SNAPSHOT
+ jar
+
+ Security
+ Demo project for Spring Boot
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 1.5.14.RELEASE
+
+
+
+
+ UTF-8
+ UTF-8
+ 1.8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+
+ org.apache.commons
+ commons-lang3
+ 3.7
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
diff --git a/35.Spring-Security-Authentication/src/main/java/cc/mrbird/SecurityApplication.java b/35.Spring-Security-Authentication/src/main/java/cc/mrbird/SecurityApplication.java
new file mode 100644
index 0000000..4740934
--- /dev/null
+++ b/35.Spring-Security-Authentication/src/main/java/cc/mrbird/SecurityApplication.java
@@ -0,0 +1,12 @@
+package cc.mrbird;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SecurityApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SecurityApplication.class, args);
+ }
+}
diff --git a/35.Spring-Security-Authentication/src/main/java/cc/mrbird/domain/MyUser.java b/35.Spring-Security-Authentication/src/main/java/cc/mrbird/domain/MyUser.java
new file mode 100644
index 0000000..dee4f7f
--- /dev/null
+++ b/35.Spring-Security-Authentication/src/main/java/cc/mrbird/domain/MyUser.java
@@ -0,0 +1,67 @@
+package cc.mrbird.domain;
+
+import java.io.Serializable;
+
+public class MyUser implements Serializable {
+ private static final long serialVersionUID = 3497935890426858541L;
+
+ private String userName;
+
+ private String password;
+
+ private boolean accountNonExpired = true;
+
+ private boolean accountNonLocked= true;
+
+ private boolean credentialsNonExpired= true;
+
+ private boolean enabled= true;
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public boolean isAccountNonExpired() {
+ return accountNonExpired;
+ }
+
+ public void setAccountNonExpired(boolean accountNonExpired) {
+ this.accountNonExpired = accountNonExpired;
+ }
+
+ public boolean isAccountNonLocked() {
+ return accountNonLocked;
+ }
+
+ public void setAccountNonLocked(boolean accountNonLocked) {
+ this.accountNonLocked = accountNonLocked;
+ }
+
+ public boolean isCredentialsNonExpired() {
+ return credentialsNonExpired;
+ }
+
+ public void setCredentialsNonExpired(boolean credentialsNonExpired) {
+ this.credentialsNonExpired = credentialsNonExpired;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+}
diff --git a/35.Spring-Security-Authentication/src/main/java/cc/mrbird/handler/MyAuthenticationFailureHandler.java b/35.Spring-Security-Authentication/src/main/java/cc/mrbird/handler/MyAuthenticationFailureHandler.java
new file mode 100644
index 0000000..22127b4
--- /dev/null
+++ b/35.Spring-Security-Authentication/src/main/java/cc/mrbird/handler/MyAuthenticationFailureHandler.java
@@ -0,0 +1,29 @@
+package cc.mrbird.handler;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.authentication.AuthenticationFailureHandler;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Component
+public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
+
+ @Autowired
+ private ObjectMapper mapper;
+
+ @Override
+ public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
+ AuthenticationException exception) throws IOException {
+ response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
+ response.setContentType("application/json;charset=utf-8");
+ response.getWriter().write(mapper.writeValueAsString(exception.getMessage()));
+ }
+}
diff --git a/35.Spring-Security-Authentication/src/main/java/cc/mrbird/handler/MyAuthenticationSucessHandler.java b/35.Spring-Security-Authentication/src/main/java/cc/mrbird/handler/MyAuthenticationSucessHandler.java
new file mode 100644
index 0000000..8dc29d3
--- /dev/null
+++ b/35.Spring-Security-Authentication/src/main/java/cc/mrbird/handler/MyAuthenticationSucessHandler.java
@@ -0,0 +1,40 @@
+package cc.mrbird.handler;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.DefaultRedirectStrategy;
+import org.springframework.security.web.RedirectStrategy;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
+import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
+import org.springframework.security.web.savedrequest.RequestCache;
+import org.springframework.security.web.savedrequest.SavedRequest;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Component
+public class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler {
+
+ // private RequestCache requestCache = new HttpSessionRequestCache();
+
+ private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
+ //
+ // @Autowired
+ // private ObjectMapper mapper;
+
+ @Override
+ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
+ Authentication authentication) throws IOException {
+ // response.setContentType("application/json;charset=utf-8");
+ // response.getWriter().write(mapper.writeValueAsString(authentication));
+ // SavedRequest savedRequest = requestCache.getRequest(request, response);
+ // System.out.println(savedRequest.getRedirectUrl());
+ // redirectStrategy.sendRedirect(request, response, savedRequest.getRedirectUrl());
+ redirectStrategy.sendRedirect(request, response, "/index");
+ }
+}
diff --git a/35.Spring-Security-Authentication/src/main/java/cc/mrbird/security/browser/BrowserSecurityConfig.java b/35.Spring-Security-Authentication/src/main/java/cc/mrbird/security/browser/BrowserSecurityConfig.java
new file mode 100644
index 0000000..92a0ea4
--- /dev/null
+++ b/35.Spring-Security-Authentication/src/main/java/cc/mrbird/security/browser/BrowserSecurityConfig.java
@@ -0,0 +1,43 @@
+package cc.mrbird.security.browser;
+
+import cc.mrbird.handler.MyAuthenticationFailureHandler;
+import cc.mrbird.handler.MyAuthenticationSucessHandler;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+@Configuration
+public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Autowired
+ private MyAuthenticationSucessHandler authenticationSucessHandler;
+
+ @Autowired
+ private MyAuthenticationFailureHandler authenticationFailureHandler;
+
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.formLogin() // 表单登录
+ // http.httpBasic() // HTTP Basic
+ .loginPage("/authentication/require") // 登录跳转 URL
+ .loginProcessingUrl("/login") // 处理表单登录 URL
+ .successHandler(authenticationSucessHandler) // 处理登录成功
+ .failureHandler(authenticationFailureHandler) // 处理登录失败
+ .and()
+ .authorizeRequests() // 授权配置
+ .antMatchers("/authentication/require", "/login.html").permitAll() // 登录跳转 URL 无需认证
+ .anyRequest() // 所有请求
+ .authenticated() // 都需要认证
+ .and().csrf().disable();
+ }
+}
diff --git a/35.Spring-Security-Authentication/src/main/java/cc/mrbird/security/browser/UserDetailService.java b/35.Spring-Security-Authentication/src/main/java/cc/mrbird/security/browser/UserDetailService.java
new file mode 100644
index 0000000..58992aa
--- /dev/null
+++ b/35.Spring-Security-Authentication/src/main/java/cc/mrbird/security/browser/UserDetailService.java
@@ -0,0 +1,32 @@
+package cc.mrbird.security.browser;
+
+import cc.mrbird.domain.MyUser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+@Configuration
+public class UserDetailService implements UserDetailsService {
+
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+
+ @Override
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+ // 模拟一个用户,替代数据库获取逻辑
+ MyUser user = new MyUser();
+ user.setUserName(username);
+ user.setPassword(this.passwordEncoder.encode("123456"));
+ // 输出加密后的密码
+ System.out.println(user.getPassword());
+
+ return new User(username, user.getPassword(), user.isEnabled(),
+ user.isAccountNonExpired(), user.isCredentialsNonExpired(),
+ user.isAccountNonLocked(), AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
+ }
+}
diff --git a/35.Spring-Security-Authentication/src/main/java/cc/mrbird/web/controller/BrowserSecurityController.java b/35.Spring-Security-Authentication/src/main/java/cc/mrbird/web/controller/BrowserSecurityController.java
new file mode 100644
index 0000000..b198589
--- /dev/null
+++ b/35.Spring-Security-Authentication/src/main/java/cc/mrbird/web/controller/BrowserSecurityController.java
@@ -0,0 +1,39 @@
+package cc.mrbird.web.controller;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.security.web.DefaultRedirectStrategy;
+import org.springframework.security.web.RedirectStrategy;
+import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
+import org.springframework.security.web.savedrequest.RequestCache;
+import org.springframework.security.web.savedrequest.SavedRequest;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * @author MrBird
+ */
+@RestController
+public class BrowserSecurityController {
+
+ private RequestCache requestCache = new HttpSessionRequestCache();
+
+ private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
+
+ @GetMapping("/authentication/require")
+ @ResponseStatus(HttpStatus.UNAUTHORIZED)
+ public String requireAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ SavedRequest savedRequest = requestCache.getRequest(request, response);
+ if (savedRequest != null) {
+ String targetUrl = savedRequest.getRedirectUrl();
+ if (StringUtils.endsWithIgnoreCase(targetUrl, ".html"))
+ redirectStrategy.sendRedirect(request, response, "/login.html");
+ }
+ return "访问的资源需要身份认证!";
+ }
+}
diff --git a/35.Spring-Security-Authentication/src/main/java/cc/mrbird/web/controller/TestController.java b/35.Spring-Security-Authentication/src/main/java/cc/mrbird/web/controller/TestController.java
new file mode 100644
index 0000000..b677e61
--- /dev/null
+++ b/35.Spring-Security-Authentication/src/main/java/cc/mrbird/web/controller/TestController.java
@@ -0,0 +1,20 @@
+package cc.mrbird.web.controller;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class TestController {
+ @GetMapping("hello")
+ public String hello() {
+ return "hello spring security";
+ }
+
+ @GetMapping("index")
+ public Object index(Authentication authentication) {
+ // return SecurityContextHolder.getContext().getAuthentication();
+ return authentication;
+ }
+}
diff --git a/35.Spring-Security-Authentication/src/main/resources/application.yml b/35.Spring-Security-Authentication/src/main/resources/application.yml
new file mode 100644
index 0000000..a618ee1
--- /dev/null
+++ b/35.Spring-Security-Authentication/src/main/resources/application.yml
@@ -0,0 +1,3 @@
+security:
+ basic:
+ enabled: true
\ No newline at end of file
diff --git a/35.Spring-Security-Authentication/src/main/resources/resources/css/login.css b/35.Spring-Security-Authentication/src/main/resources/resources/css/login.css
new file mode 100644
index 0000000..52d1699
--- /dev/null
+++ b/35.Spring-Security-Authentication/src/main/resources/resources/css/login.css
@@ -0,0 +1,97 @@
+.login-page {
+ width: 360px;
+ padding: 8% 0 0;
+ margin: auto;
+}
+.form {
+ position: relative;
+ z-index: 1;
+ background: #ffffff;
+ max-width: 360px;
+ margin: 0 auto 100px;
+ padding: 45px;
+ text-align: center;
+ box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24);
+}
+.form input {
+ outline: 0;
+ background: #f2f2f2;
+ width: 100%;
+ border: 0;
+ margin: 0 0 15px;
+ padding: 15px;
+ box-sizing: border-box;
+ font-size: 14px;
+}
+.form button {
+ text-transform: uppercase;
+ outline: 0;
+ background: #4caf50;
+ width: 100%;
+ border: 0;
+ padding: 15px;
+ color: #ffffff;
+ font-size: 14px;
+ -webkit-transition: all 0.3 ease;
+ transition: all 0.3 ease;
+ cursor: pointer;
+}
+.form button:hover,
+.form button:active,
+.form button:focus {
+ background: #43a047;
+}
+.form .message {
+ margin: 15px 0 0;
+ color: #b3b3b3;
+ font-size: 12px;
+}
+.form .message a {
+ color: #4caf50;
+ text-decoration: none;
+}
+.form .register-form {
+ display: none;
+}
+.container {
+ position: relative;
+ z-index: 1;
+ max-width: 300px;
+ margin: 0 auto;
+}
+.container:before,
+.container:after {
+ content: "";
+ display: block;
+ clear: both;
+}
+.container .info {
+ margin: 50px auto;
+ text-align: center;
+}
+.container .info h1 {
+ margin: 0 0 15px;
+ padding: 0;
+ font-size: 36px;
+ font-weight: 300;
+ color: #1a1a1a;
+}
+.container .info span {
+ color: #4d4d4d;
+ font-size: 12px;
+}
+.container .info span a {
+ color: #000000;
+ text-decoration: none;
+}
+.container .info span .fa {
+ color: #ef3b3a;
+}
+body {
+ background: #76b852; /* fallback for old browsers */
+ background: -webkit-linear-gradient(right, #76b852, #8dc26f);
+ background: -moz-linear-gradient(right, #76b852, #8dc26f);
+ background: -o-linear-gradient(right, #76b852, #8dc26f);
+ background: linear-gradient(to left, #76b852, #8dc26f);
+ font-family: Lato,"PingFang SC","Microsoft YaHei",sans-serif;
+}
diff --git a/35.Spring-Security-Authentication/src/main/resources/resources/login.html b/35.Spring-Security-Authentication/src/main/resources/resources/login.html
new file mode 100644
index 0000000..dc0ff80
--- /dev/null
+++ b/35.Spring-Security-Authentication/src/main/resources/resources/login.html
@@ -0,0 +1,18 @@
+
+
+
+
+ 登录
+
+
+
+
+
+
\ No newline at end of file