一人得道雞犬升天
得益於springboot起步依賴、自動配置,spring security在繁雜的配置中解脫出來,一個重量級安全框架重換新生。
我們看看springboot中spring security玩法,spring cloud也是一脈相承呀。
第一步曲~初探
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
我們加入依賴後便使用起來了security,系統生成隨機密碼。
我們的請求就被攔截了
1:自定義密碼
application.yml
String:
application:
name: rabbitmq_cons_demo
security:
user:
name:admin
password:123456
2:權限處理
java代碼在內存中配置
新建Security 核心配置類繼承WebSecurityConfigurerAdapter
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.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.io.PrintWriter;
/**
* @author liuzonghua
* @Package com.example.
* @Description:
* @date 2020/5/7 9:26
*/
@Configuration
@EnableWebSecurity // 啓用Spring Security的Web安全支持
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 將用戶設置在內存中
* @param auth
* @throws Exception
*/
@Autowired
public void config(AuthenticationManagerBuilder auth) throws Exception {
// 在內存中配置用戶,配置多個用戶調用`and()`方法
auth.inMemoryAuthentication()
.passwordEncoder(passwordEncoder()) // 指定加密方式
.withUser("admin").password(passwordEncoder().encode("123456")).roles("ADMIN")
.and()
.withUser("test").password(passwordEncoder().encode("123456")).roles("USER");
}
@Bean
public PasswordEncoder passwordEncoder() {
// BCryptPasswordEncoder:Spring Security 提供的加密工具,可快速實現加密加鹽
return new BCryptPasswordEncoder();
}
/**
* 登錄處理
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
// 開啓登錄配置
http.authorizeRequests()
// 標識訪問 `/index` 這個接口,需要具備`ADMIN`角色
.antMatchers("/index").hasRole("ADMIN")
// 允許匿名的url - 可理解爲放行接口 - 多個接口使用,分割
.antMatchers("/", "/home").permitAll()
// 其餘所有請求都需要認證
.anyRequest().authenticated()
.and()
// 設置登錄認證頁面
.formLogin().loginPage("/login")
// 登錄成功後的處理接口 - 方式①
.loginProcessingUrl("/home")
// 自定義登陸用戶名和密碼屬性名,默認爲 username和password
.usernameParameter("username")
.passwordParameter("password")
// 登錄成功後的處理器 - 方式②
// .successHandler((req, resp, authentication) -> {
// resp.setContentType("application/json;charset=utf-8");
// PrintWriter out = resp.getWriter();
// out.write("登錄成功...");
// out.flush();
// })
// 配置登錄失敗的回調
.failureHandler((req, resp, exception) -> {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write("登錄失敗...");
out.flush();
})
.permitAll()//和表單登錄相關的接口統統都直接通過
.and()
.logout().logoutUrl("/logout")
// 配置註銷成功的回調
.logoutSuccessHandler((req, resp, authentication) -> {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write("註銷成功...");
out.flush();
})
.permitAll()
.and()
.httpBasic()
.and()
// 關閉CSRF跨域
.csrf().disable();
}
/**
* 忽略攔截
* @param web
* @throws Exception
*/
@Override
public void configure(WebSecurity web) throws Exception {
// 設置攔截忽略url - 會直接過濾該url - 將不會經過Spring Security過濾器鏈
web.ignoring().antMatchers("/getUserInfo");
// 設置攔截忽略文件夾,可以對靜態資源放行
web.ignoring().antMatchers("/css/**", "/js/**");
}
}
第二步曲~自定義登錄認證處理
配置用戶密碼校驗過濾器
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 用戶密碼校驗過濾器
*/
private final AdminAuthenticationProcessingFilter adminAuthenticationProcessingFilter;
public SecurityConfig(AdminAuthenticationProcessingFilter adminAuthenticationProcessingFilter) {
this.adminAuthenticationProcessingFilter = adminAuthenticationProcessingFilter;
}
/**
* 權限配置
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.antMatcher("/**").authorizeRequests();
// 禁用CSRF 開啓跨域
http.csrf().disable().cors();
// 登錄處理 - 前後端一體的情況下
// registry.and().formLogin().loginPage("/login").defaultSuccessUrl("/").permitAll()
// // 自定義登陸用戶名和密碼屬性名,默認爲 username和password
// .usernameParameter("username").passwordParameter("password")
// // 異常處理
// .failureUrl("/login/error").permitAll()
// // 退出登錄
// .and().logout().permitAll();
// 標識只能在 服務器本地ip[127.0.0.1或localhost] 訪問`/home`接口,其他ip地址無法訪問
registry.antMatchers("/home").hasIpAddress("127.0.0.1");
// 允許匿名的url - 可理解爲放行接口 - 多個接口使用,分割
registry.antMatchers("/login", "/index").permitAll();
// OPTIONS(選項):查找適用於一個特定網址資源的通訊選擇。 在不需執行具體的涉及數據傳輸的動作情況下, 允許客戶端來確定與資源相關的選項以及 / 或者要求, 或是一個服務器的性能
registry.antMatchers(HttpMethod.OPTIONS, "/**").denyAll();
// 自動登錄 - cookie儲存方式
registry.and().rememberMe();
// 其餘所有請求都需要認證
registry.anyRequest().authenticated();
// 防止iframe 造成跨域
registry.and().headers().frameOptions().disable();
// 自定義過濾器認證用戶名密碼
http.addFilterAt(adminAuthenticationProcessingFilter, UsernamePasswordAuthenticationFilter.class);
}
}