æ¦è¿°
Spring Securityæ¯ä¸ºJavaåºç¨ç¨åºæä¾èº«ä»½éªè¯åææ ã
ä¸è¬Webåºç¨çéè¦è¿è¡è®¤è¯åææã
认è¯ï¼Authenticationï¼ï¼éªè¯å½å访é®ç³»ç»çæ¯ä¸æ¯æ¬ç³»ç»çç¨æ·ï¼å¹¶ä¸è¦ç¡®è®¤å ·ä½æ¯åªä¸ªç¨æ·ã
â ææï¼Authorizationï¼ï¼ç»è¿è®¤è¯åå¤æå½åç¨æ·æ¯å¦ææéè¿è¡æ个æä½(访é®æ个controllerå±çæ¹æ³)ã
å ³é®æ¥å£
UserDetailsService
å¯ä»¥çåæ¯æ ¹æ®ç¨æ·åæ¥è¯¢æ°æ®åºæè ä»å åæ»è·åå¯ç ï¼æéï¼è§è²çä¿¡æ¯ã
public interface UserDetailsService {
UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}
PasswordEncoder
è¿è¡å¯ç å å¯åå¹é
public interface PasswordEncoder {
String encode(CharSequence var1);
boolean matches(CharSequence var1, String var2);
default boolean upgradeEncoding(String encodedPassword) {
return false;
}
}
å¨passwordEncoderçå®ç°ç±»ä¸ï¼BCryptPasswordEncoder æ¯ Spring Security å®æ¹æ¨èçå¯ç 解æå¨ãBCryptPasswordEncoder æ¯å¯¹ bcrypt 强æ£åæ¹æ³çå ·ä½å®ç°ãæ¯åºäº Hash ç®æ³å®ç°çååå å¯ãå¯ä»¥éè¿å¨æé å½æ°ä¸ä¼ å ¥strength æ§å¶å å¯å¼ºåº¦ï¼é»è®¤ 10ã
strengthçèå´å¨[4,31],å¯ä»¥å¨BCryptPasswordEncoder ä¸å¯ä»¥çå°ï¼ä¸åspringbootæå¯è½ä¸åã
public BCryptPasswordEncoder(BCryptPasswordEncoder.BCryptVersion version, int strength, SecureRandom random) {
this.BCRYPT_PATTERN = Pattern.compile("\\A\\$2(a|y|b)?\\$(\\d\\d)\\$[./0-9A-Za-z]{53}");
this.logger = LogFactory.getLog(this.getClass());
if (strength == -1 || strength >= 4 && strength <= 31) {
this.version = version;
this.strength = strength == -1 ? 10 : strength;
this.random = random;
} else {
throw new IllegalArgumentException("Bad strength");
}
}
设置ç¨æ·ååå¯ç
- application.yaml
server:
port: 9000
spring:
security:
user:
name: user
password: 123
è¿ç§ç¯å¢ä¸ä¸è½é ç½®WebSecurityConfigurerAdapterçå®ç°ç±» å¦åé ç½®ç¨æ·ååå¯ç æ æ
2. å¨å åä¸è®¾ç½®
spring securityä¸é»è®¤ç»å½æ¦æªuriæ¯/login
package com.kj.config;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 注æè¿ééè¦å¯ç éè¦å å¯ åæ¶éè¦è®¾ç½®roles
// å¦åä¼æåºå¼å¸¸ java.lang.IllegalArgumentException: Cannot pass a null GrantedAuthority collection
auth.inMemoryAuthentication().withUser("root").password(passwordEncoder.encode("123")).roles("");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// å¼å¯è¡¨åç»å½éªè¯
http.formLogin();
// è¿ééè¦è®¾ç½®å¤çloginæ¥å£ä¹å¤çå
¶ä»è¯·æ±éè¦è®¤è¯
http.authorizeRequests().antMatchers("/login").permitAll().anyRequest().authenticated();
// ææ¶å
³écsrf å¦åå¨ç»å½æ¯éè¦ä¼ éå
¶ä»åæ°
http.csrf().disable();
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
è¿écsrfé»è®¤å¼å¯ï¼åæ¶springsecurityé»è®¤ä¸å¼å¯è®¤è¯ï¼ææéè¦é对é¤äºloginæ¥å£å¤çå ¶ä»æ¥å£é½éè¦è®¤è¯ãå½ç¶ï¼å¯¹äºæäºå ¬å ±çéæèµæºè¿éä¹å¯ä»¥è®¾ç½®ï¼ä¸ºäºæ¼ç¤ºç®åäºè®¾ç½®ã
ä¹å¯ä»¥åæ¶è®¾ç½®å¤ä¸ªå 容ä¸çç¨æ·
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
inMemoryUserDetailsManager.createUser(User.withUsername("admin").password(passwordEncoder.encode("123")).roles("admin").build());
inMemoryUserDetailsManager.createUser(User.withUsername("root").password(passwordEncoder.encode("456")).roles("root").build());
auth.userDetailsService(inMemoryUserDetailsManager).passwordEncoder(passwordEncoder);
}
3.èªå®ä¹UserDetailService
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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 java.util.ArrayList;
import java.util.List;
public class UserDetailsServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
// æ¥è¯¢æ°æ®åº è·åç¨æ·çå¯ç ï¼è§è²ï¼æéçä¿¡æ¯ å¡«å
String pwd="";
String[] roles;
String[] authorities;
List<GrantedAuthority> auths=new ArrayList<>();
for (String role : roles) {
auths.add(new SimpleGrantedAuthority("ROLE_"+role);
}
for (String authority : authorities) {
auths.add(new SimpleGrantedAuthority(authority));
}
return new User(s,pwd,auths);
}
}
WebSecurityConfigurerAdapteré ç½®èªå®ä¹çUserDetailService
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new UserDetailsServiceImpl()).passwordEncoder(passwordEncoder);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin();
http.authorizeRequests().antMatchers("/login").permitAll();
http.csrf().disable();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
è§è²åæé
è§è²åæéä¹æ¯ Spring Security ä¸æéç¨çææ模åãGrantedAuthority 对象代表çå°±æ¯ä¸ç§æé对象ï¼æ¯ä¸ä¸ªæ¥å£ï¼å®æ¢å¯ä»¥çåæ¯æéï¼åæ¶ä¹å¯ä»¥çåæ¯è§è²ï¼éè¦æ·»å ROLE_åç¼ã代ç å¦ä¸:
public interface GrantedAuthority extends Serializable {
String getAuthority();
}
å建æé
对äºrootç¨æ·å ·æäºcreate,deleteæé
UserDetails user = User.withUsername("root")
.password("123456")
.authorities("create", "delete")
.build();
å建è§è²
UserDetails user = User.withUsername("yn")
.password("123456")
.authorities("ROLE_ADMIN")
.build();
å建è§è²åæé
List<GrantedAuthority> auths= AuthorityUtils.commaSeparatedStringToAuthorityList("test,ROLE_normal");
User user=new User("test",passwordEncoder.encode("789"),auths);
è§è²ç»§æ¿
@Bean
RoleHierarchy roleHierarchy() {
RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
hierarchy.setHierarchy("ROLE_admin > ROLE_user");
return hierarchy;
}
注æï¼å¨é ç½®æ¶ï¼éè¦ç»è§è²æå¨å ä¸ ROLE_ åç¼ãä¸é¢çé 置表示 ROLE_admin èªå¨å ·å¤ ROLE_user çæéãå¦ææå¤ä¸ª\nè¿è¡åå²
å®é ä¸å¯ä»¥èè使ç¨æéç»çå½¢å¼æ¥ä»£æ¿è¿ç§ç»§æ¿
è§è²åæéæ ¡éª
api | ä½ç¨ |
anonymous | å 许å¿åè®¿é® |
authenticated | å 许认è¯ç¨æ·è®¿é® |
denyAll | æ æ¡ä»¶ç¦æ¢ä¸åè®¿é® |
hasAnyAuthority | å è®¸å ·æä»»ä¸æéçç¨æ·è¿è¡è®¿é® |
hasAnyRole | å è®¸å ·æä»»ä¸è§è²çç¨æ·è¿è¡è®¿é® |
hasAuthority | å è®¸å ·æç¹å®æéçç¨æ·è¿è¡è®¿é® |
hasIpAddress | å 许æ¥èªç¹å® IP å°åçç¨æ·è¿è¡è®¿é® |
hasRole | å è®¸å ·æç¹å®è§è²çç¨æ·è¿è¡è®¿é® |
permitAll | æ æ¡ä»¶å 许ä¸åè®¿é® |
apiå¼æ ¡éª
eg:
@Override
protected void configure(HttpSecurity http) throws Exception
http.formLogin();
// è¿éRoleä¸ç¨å åç¼
http.authorizeRequests().antMatchers("/login").permitAll()
.antMatchers("/port").hasRole("admin");//
http.csrf().disable();
}
æ³¨è§£æ ¡éª
@Secured
åªè½ç¨äºæéç¨æ·å ·ææ个æé(è§è²(éè¦å åç¼)æè æé)æè½è®¿é®è¯¥æ¹æ³,é¦å éè¦å¨ä¸»å¯å¨ç±»ä¸å¼å¯()ï¼ç¶åå¨å¯¹åºcontrolleræ¹æ³ä¸å¼å¯
@SpringBootApplication
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityApplication.class,args);
}
}
@GetMapping("/port")
@Secured("ROLE_root")
public String getPort(){
return this.port;
}
PreAuthorize
æ¹æ³ä¹åæ£éª
主å¯å¨ç±»ä¸æ·»å @EnableGlobalMethodSecurity(prePostEnabled =true)
@SpringBootApplication
@EnableGlobalMethodSecurity(prePostEnabled =true)
public class SecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityApplication.class,args);
}
}
@GetMapping("/port")
@PreAuthorize("hasRole('root')")
public String getPort(){
return this.port;
}
PostAuthroize
æ¹æ³ä¹åæ ¡éª
主å¯å¨ç±»ä¸æ·»å @EnableGlobalMethodSecurity(prePostEnabled =true),å é¨è°ç¨ä¹åçapi
@SpringBootApplication
@EnableGlobalMethodSecurity(prePostEnabled =true)
public class SecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityApplication.class,args);
}
}
@GetMapping("/port")
@PostAuthorize("hasRole('root')")
public String getPort(){
return this.port;
}
PreFilter
è¿å ¥æ§å¶å¨ä¹å对æ°æ®è¿è¡è¿æ»¤ï¼è¦æ±ä¼ å ¥çå¿ é¡»æ¯collectionæè æ¯æ°ç» ,è¿ä»£æ¶å ç´ å«å为filterObject
@SpringBootApplication
@EnableGlobalMethodSecurity(prePostEnabled =true)
public class SecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityApplication.class,args);
}
}
//studentä¸id为å¶æ°çä¿ç
@GetMapping("/port")
@PreFilter(value = "filteObject.id%2==0")
public String getPort(List<Student> students){
return this.port;
}
PostFilter
æééªè¯ä¹å对æ°æ®è¿è¡è¿æ»¤
@SpringBootApplication
@EnableGlobalMethodSecurity(prePostEnabled =true)
public class SecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityApplication.class,args);
}
}
//studentä¸id为å¶æ°çè¿å
@GetMapping("/port")
@PreFilter(value = "filteObject.id%2==0")
public List<Student> getPort(){
return null;
}
ç»åº
éåºç»å½åéè¦è®¾ç½®æ¸ é¤cookie,session,认è¯ä¿¡æ¯ è¿äºé½æ¯é»è®¤çï¼å¯ä»¥ä¸ç¨é ç½®ã
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin();
http.authorizeRequests().antMatchers("/login").permitAll();
//设置éåºç»å½çæ¥å£ä»¥åæ¹æ³ï¼é»è®¤æ¯getï¼åæ¶å¯ä»¥è®¾ç½®ç»åºæååè°
http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout", "DELETE"))
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
// åå端å离 ä¸å¯ä»¥éè¿HttpServletResponseè¿å jsonä¿¡æ¯
}
});
http.csrf().disable();
}
èªå®ä¹è®¿é®çé¢
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// èªå®ä¹ç»éçé¢åæååç页é¢
@Override
protected void configure(HttpSecurity http) throws Exception{
http.formLogin()
.loginPage("/index")
.loginProcessingUrl("/login") //å表åéçactionå±æ§è¦ä¸æ · 表åä¸å®æ¯post请æ±
.defaultSuccessUrl("/success") //设置äºæåå失败çURL 就跳转å°åæ¥è¦è®¿é®çå°å
.failureForwardUrl("/fail")
.passwordParameter("pwd") //æå®è¡¨åéçå±æ§å
.usernameParameter("uname");
http.authorizeRequests().antMatchers("/login").permitAll()
.anyRequest().authenticated();
http.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
String encode = passwordEncoder().encode("123");
auth.inMemoryAuthentication().withUser("user").password(encode).roles("admin");
}
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
ç»å½æåå失败çURL
å¨ Spring Security ä¸ï¼åç»å½æåéå®å URL ç¸å ³çæ¹æ³æ两个ï¼
- defaultSuccessUrlï¼urlï¼ï¼å¦æä¸å¼å§è®¿é®çæ¯ç»å½æ¥å£ï¼ä¼è·³è½¬å°urlä¸ï¼å¦åä¸å¼å§è®¿é®çæ¯å ¶ä»æ¥å£ï¼å°±ä¼è·³è½¬å°å¯¹åºçæ¥å£ï¼
- successForwardUrl(url) (ä¸ç®¡ç»å½å访é®çæ¯ä»ä¹æ¥å£ï¼ç»å½æååé½è·³è½¬å°æå®çURL)
失败çURL
ä¸ç»å½æåç¸ä¼¼ï¼ç»å½å¤±è´¥ä¹æ¯æ两个æ¹æ³ï¼
- failureForwardUrl
- failureUrl
è¿ä¸¤ä¸ªæ¹æ³å¨è®¾ç½®çæ¶åä¹æ¯è®¾ç½®ä¸ä¸ªå³å¯ãfailureForwardUrl æ¯ç»å½å¤±è´¥ä¹åä¼åçæå¡ç«¯è·³è½¬ï¼failureUrl åå¨ç»å½å¤±è´¥ä¹åï¼ä¼åçéå®åã
å¨åå端å离ç项ç®ä¸ï¼é¡µé¢è°æ´æ¯ç±å端æ§å¶çï¼ç¸å¯¹æ¥è¯´ç¨çå°ã
ä¸äºåè°æ¥å£
æ¥å£
常ç¨çä¸äºæ©å±æ¥å£
- AuthenticationSuccessHandlerï¼ç»å½æåå¤çï¼
- AuthenticationFailureHandlerï¼ç»å½å¤±è´¥å¤çï¼
- logoutSuccessHandlerï¼æ³¨éæåå¤çï¼
- logHandlerï¼æ³¨éå¤çï¼
- AccessDeniedHandlerï¼è®¿é®æç»å¤çï¼
- AuthenticationEntryPointï¼èº«ä»½éªè¯å ¥å£ç¹å¤±è´¥å¤çï¼
AuthenticationEntryPoint ç¨æ¥è§£å³å¿åç¨æ·è®¿é®æ æéèµæºæ¶çå¼å¸¸
AccessDeineHandler ç¨æ¥è§£å³è®¤è¯è¿çç¨æ·è®¿é®æ æéèµæºæ¶çå¼å¸¸
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin();
http.authorizeRequests().antMatchers("/login").permitAll();
http.formLogin().successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
// ç»å½æå对è°
}
});
http.formLogin().failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
// ç»å½å¤±è´¥åè°
}
});
http.logout().logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
// ç»åºæååè°
}
});
// ç»åºå¤ç
http.logout().addLogoutHandler(...)
http.csrf().disable();
}
csrf
csrfæ¯æç¨æ·å¯¹æµè§å¨çä¿¡ä»»ï¼ç¬¬ä¸æ¹ï¼å©ç¨ä¸äºææ¯æ段ï¼æ¬ºéªç¨æ·è®¿é®ï¼è®¤è¯è¿çé¾æ¥ï¼è®¤è¯è¿ï¼å°±ä¼æºå¸¦å¯¹åºçcookieï¼å¯¹ç¨æ·æ¶ææ»å»ã
解å³æ¹æ¡ä¹ä¸
令çåæ¥æ¨¡å¼
è¿æ¯ç®å主æµçCSRF æ»å»é²å¾¡æ¹æ¡ãå ·ä½çæä½æ¹å¼å°±æ¯å¨æ¯ä¸ä¸ªHTTP请æ±ä¸ï¼é¤äºé»è®¤èªå¨æºå¸¦çCookie åæ°ä¹å¤ï¼åæä¾ä¸ä¸ªå®å ¨çãéæºçæçå®ç¬¦ä¸²ï¼æ们称ä¹ä¸ºCSRF令çãè¿ä¸ªCSRF令çç±æå¡ç«¯çæï¼çæåå¨HtpSessionä¸ä¿åä¸ä»½ãå½å端请æ±å°è¾¾åï¼å°è¯·æ±æºå¸¦çCSRF令çä¿¡æ¯åæå¡ç«¯ä¸ä¿åç令çè¿è¡å¯¹æ¯ï¼å¦æ两è ä¸ç¸çï¼åæç»æ该HITTP请æ±ã
注æ:èèå°ä¼æä¸äºå¤é¨ç«ç¹é¾æ¥å°æ们çç½ç«ï¼æ以æ们è¦æ±è¯·æ±æ¯å¹ççï¼è¿æ ·å¯¹åHEADãOPTIONSãTRACEçæ¹æ³å°±æ²¡æå¿ è¦ä½¿ç¨CSRF令çäºï¼å¼ºè¡ä½¿ç¨å¯è½ä¼å¯¼è´ä»¤çæ³é²!
spring securityé»è®¤å¼å¯csrf,ä¸ç¨é ç½®ã
åå端å离项ç®ä¸ï¼ä¸å¼å§åºè¯¥åé两次请æ±ï¼ç¬¬ä¸æ¬¡ä¼è·åcsrf令ç ä¿åå¨cookieéï¼ä¹åæç §ä¸å®æ¹å¼ç»è£ csrf令çï¼ç¶åæ交ã
cookieékey: XSRF-TOKEN
åå端å离çç»è£ æ¹å¼
value为tokenå¼
1 jsonæ ¼å¼è¯·æ±
//请æ±é¢éæ·»å
_csrf:value
2 http-headerä¸æ·»å
//valueä»cookieä¸è·å
X-XSRF-TOKEN:value
remember-me
åºæ¬é ç½®
è®°ä½æçåè½å®ç°æè·¯åºæ¬æ¯åºäºtokenï¼åæ¶è¦èètokenæ¯å¦è¿æçæ åµï¼ä»¥åæ¯å¦æ´æ°ã
spring securityéçtokenéä¿çäºç¨æ·åï¼è¿ææ¶é´ï¼è¿æå ¶ä»çä¸äºä¿¡æ¯ï¼è¿åçæ¯ç»è¿Base64ç¼ç åçtokenã
tokenççæéè¦keyï¼key é»è®¤å¼æ¯ä¸ä¸ª UUID å符串ï¼è¿æ ·ä¼å¸¦æ¥ä¸ä¸ªé®é¢ï¼å°±æ¯å¦ææå¡ç«¯éå¯ï¼è¿ä¸ª key ä¼åï¼è¿æ ·å°±å¯¼è´ä¹åæ´¾ååºå»çææ remember-me èªå¨ç»å½ä»¤ç失æï¼æ以ï¼æ们å¯ä»¥æå®è¿ä¸ª key
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.rememberMe()
.key("salt")
.and()
.csrf().disable();
}
å¦æè¦éè¿è¡¨åä¼ érememberMe key为remember-me
<div> Remember Meï¼<input type="checkbox" name="remember-me" value="true"/> </div>
tokenæä¹ å
tokenåå¨é»è®¤æ¯åºäºå åçï¼æå¡å¨å¦æéå¯ï¼ä¿¡æ¯å°±ä¼ä¸¢å¤±ãtokenéè¦æä¹ åå¨æ°æ®åºéã
ä¿åTokenç«ççç±»æ¯PersistentRememberMeToken
public class PersistentRememberMeToken {
private final String username;
private final String series;
private final String tokenValue;
private final Date date;
}
对åºçSQLèæ¬ä¸º
CREATE TABLE `persistent_logins`
`username` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
`series` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
`token` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
`last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`series`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
æå ³åå¨çç±»æ¯JdbcTokenRepositoryImpl
ç¸å ³çé ç½®
æ°æ®åº
å¼å ¥mysqlç驱å¨åå¨application.yamléé ç½®æ°æ®åºå°å
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.24</version>
</dependency>
application.yaml
server:
port: 9000
spring:
datasource:
url: jdbc:mysql://127.0.0.1/sec?serverTimezone=UTC&useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
securityé ç½®
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import javax.sql.DataSource;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
DataSource dataSource;
@Bean
JdbcTokenRepositoryImpl jdbcTokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
return jdbcTokenRepository;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new UserDetailsServiceImpl()).passwordEncoder(passwordEncoder);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin();
http.authorizeRequests().antMatchers("/login").permitAll();
http.rememberMe().key("salt").tokenRepository(jdbcTokenRepository());
http.csrf().disable();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
äºæ¬¡æ ¡éª
为äºè®©ç¨æ·ä½¿ç¨æ¹ä¾¿ï¼æ们å¼éäºèªå¨ç»å½åè½ï¼ä½æ¯èªå¨ç»å½åè½å带æ¥äºå®å ¨é£é©ï¼ä¸ä¸ªè§é¿çåæ³å°±æ¯å¦æç¨æ·ä½¿ç¨äºèªå¨ç»å½åè½ï¼æ们å¯ä»¥åªè®©ä»åä¸äºå¸¸è§çä¸æææä½ï¼ä¾å¦æ°æ®æµè§ãæ¥çï¼ä½æ¯ä¸å 许ä»åä»»ä½ä¿®æ¹ãå é¤æä½ï¼å¦æç¨æ·ç¹å»äºä¿®æ¹ãå é¤æé®ï¼æ们å¯ä»¥è·³è½¬åç»å½é¡µé¢ï¼è®©ç¨æ·éæ°è¾å ¥å¯ç 确认身份ï¼ç¶ååå 许ä»æ§è¡æææä½ã
ä¾å¦æç°å¨æä¾ä¸ä¸ªè®¿é®æ¥å£ï¼
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
@GetMapping("/admin")
public String admin() {
return "admin";
}
@GetMapping("/rememberme")
public String rememberme() {
return "rememberme";
}
}
- 第ä¸ä¸ª /hello æ¥å£ï¼åªè¦è®¤è¯åå°±å¯ä»¥è®¿é®ï¼æ 论æ¯éè¿ç¨æ·åå¯ç 认è¯è¿æ¯éè¿èªå¨ç»å½è®¤è¯ï¼åªè¦è®¤è¯äºï¼å°±å¯ä»¥è®¿é®ã
- 第äºä¸ª /admin æ¥å£ï¼å¿ é¡»è¦ç¨æ·åå¯ç 认è¯ä¹åæè½è®¿é®ï¼å¦æç¨æ·æ¯éè¿èªå¨ç»å½è®¤è¯çï¼åå¿ é¡»éæ°è¾å ¥ç¨æ·åå¯ç æè½è®¿é®è¯¥æ¥å£ã
- 第ä¸ä¸ª /rememberme æ¥å£ï¼å¿ é¡»æ¯éè¿èªå¨ç»å½è®¤è¯åæè½è®¿é®ï¼å¦æç¨æ·æ¯éè¿ç¨æ·å/å¯ç 认è¯çï¼åæ æ³è®¿é®è¯¥æ¥å£ã
æ¥å£ç访é®é ç½®å¦ä¸
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/rememberme").rememberMe()
.antMatchers("/admin").fullyAuthenticated()
.anyRequest().authenticated()
.and()
.formLogin();
}