如何建立一個spring security項目
- 寫個demo很簡單,建立springboot項目,添加web和security依賴
- 自己随便寫個接口
public class HelloController { @GetMapping("/hello") public String helloController(){ return "hello security"; }
- 啟動項目 localhost:8080/hello 自動重定向到login并顯示登陸界面
- 使用者名user,密碼springboot自動生成,控制台複制即可
spring security簡單入門
如何在配置使用者名密碼
- 在配置檔案(application properties)中配置
spring.security.user.name=ajian
spring.security.user.password=123456
spring.security.user.roles=admin
- 在代碼中配置
package com.example.security.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance(); //單例模式對象不能new出來,隻能通過getInstance方法
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("ajian").password("123").roles("admin")
.and()
.withUser("laji").password("happy520").roles("user");
}
}
自定義安全配置,使得隻有認證過的使用者才可以通路到頁面
package com.example.security.config;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance(); //單例模式對象不能new出來,隻能通過getInstance方法
} //密碼需要加密,後面解決。
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("ajian").password("123").roles("admin")
.and()
.withUser("laji").password("happy520").roles("user");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()開啟登入配置
.antMatchers("/admin/**").hasRole("admin")//表示通路 /hello 這個接口,需要具備 admin 這個角色
.antMatchers("/user/**").hasAnyRole("admin","user")
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/doLogin")//登入處理接口
.permitAll()
.and()
.csrf().disable();
}
}
controller裡面也寫相應的方法 postman進行測試
表單登陸詳細配置
具體參數如下https://blog.csdn.net/yin380697242/article/details/51893397
package com.example.security.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.*;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance(); //單例模式對象不能new出來,隻能通過getInstance方法
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("ajian").password("123").roles("admin")
.and()
.withUser("laji").password("happy520").roles("user");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()開啟登入配置
.antMatchers("/admin/**").hasRole("admin")//表示通路 /hello 這個接口,需要具備 admin 這個角色
.antMatchers("/user/**").hasAnyRole("admin","user")
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/doLogin")//登入處理接口
.loginPage("/login")
.usernameParameter("username")
.passwordParameter("password")
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
Map<String,Object> map=new HashMap<>();
map.put("status",200);
map.put("msg",authentication.getPrincipal());
out.write(new ObjectMapper().writeValueAsString(map)); //把一個對象轉成json字元串
out.flush();
out.close();
}
})
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException e) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
Map<String,Object> map=new HashMap<>();
map.put("status",401);
if( e instanceof LockedException){
map.put("msg","賬戶被鎖定了");
}else if(e instanceof BadCredentialsException){
map.put("msg","使用者名或密碼輸入錯誤,登陸失敗");
}else if(e instanceof DisabledException){
map.put("msg","賬戶被禁用,登陸失敗");
}else if(e instanceof AccountExpiredException){
map.put("msg","賬戶過期,登陸失敗");
}else if(e instanceof CredentialsExpiredException){
map.put("msg","密碼過期,登陸失敗");
}
out.write(new ObjectMapper().writeValueAsString(map)); //把一個對象轉成json字元串
out.flush();
out.close();
}
})
.permitAll()
.and()
.csrf().disable();
}
}
登出登入配置
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
Map<String,Object> map=new HashMap<>();
map.put("status",200);
map.put("msg","登出登陸成功");
out.write(new ObjectMapper().writeValueAsString(map)); //把一個對象轉成json字元串
out.flush();
out.close();
}
})
解決密碼加密問題
先用BCryptPasswordEncoder生成,真實的開發情況肯定是使用者通過這個util加密後存入資料庫的,這裡隻模拟這種情況
@Test
void contextLoads() {
for(int i=0;i<10;i++){
BCryptPasswordEncoder bcencoder = new BCryptPasswordEncoder();
System.out.println(bcencoder.encode("123"));
}
}
把列印出來的密碼換掉原來的明文密碼在securityConfig裡面
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("ajian").password("$2a$10$Kl3o4ubuwdyC8VAMI4CE1.SZSBgEcGm1ap8h6ZGUhywrIi6ZCKec2").roles("admin")
.and()
.withUser("laji").password("$2a$10$.7e3IGQqXP1vU69lY1/DWeOVRm/aFa/DYMToTZcwZtpX3eFTbFTSS").roles("user");
}
方法安全(某些角色才能調用某些方法)
securityconfig上
//配置類上加注解
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {.......}
加入service methodSerice類
package com.example.security.serivce;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
@Service
public class MethodService {
@PreAuthorize("hasRole('admin')")
public String admin(){
return "hello admin";
}
@Secured("ROLE_user")
public String user(){
return "hello user";
}
@PreAuthorize("hasAnyRole('admin','user')")
public String hello(){
return "hello hello";
}
}
加一下controller裡面的接口
@GetMapping("/admin")
public String admin(){
return methodService.admin();
}
@GetMapping("/user")
public String user(){
return methodService.user();
}
@GetMapping("/hello1")
public String hello(){
return methodService.hello();
}
測試一下
簡單入門案例github位址 連結