准备前提条件:已搭好一个spring boot后台项目及vue前台项目
目录
2、继承WebSecurityConfigurerAdapter适配器
3、自定义用户名密码校验 MyAuthenticationProvider
4、登录成功处理逻辑 CustomizeAuthenticationSuccessHandler
5、登录失败处理逻辑 CustomizeAuthenticationFailureHandler
6、匿名用户访问无权限资源时的异常处理 CustomizeAuthenticationEntryPoint
7、会话失效(账号被挤下线)处理逻辑 CustomizeSessionInformationExpiredStrategy
8、登出成功处理逻辑 CustomizeLogoutSuccessHandler
9、UserDetailsService 的实现 UserDetailsServiceImpl
10、访问权限过滤器 AuthorizationFilter
一、后台
1、依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.60</version>
</dependency>
<dependency>
<groupId>net.minidev</groupId>
<artifactId>json-smart</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
2、继承WebSecurityConfigurerAdapter适配器
import com.example.office.filter.AuthorizationFilter;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import javax.sql.DataSource;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
// 自定义用户名密码校验
@Autowired
MyAuthenticationProvider myAuthenticationProvider;
//登录成功处理逻辑
@Autowired
CustomizeAuthenticationSuccessHandler authenticationSuccessHandler;
//登录失败处理逻辑
@Autowired
CustomizeAuthenticationFailureHandler authenticationFailureHandler;
//匿名用户访问无权限资源时的异常
@Autowired
CustomizeAuthenticationEntryPoint authenticationEntryPoint;
//会话失效(账号被挤下线)处理逻辑
@Autowired
CustomizeSessionInformationExpiredStrategy sessionInformationExpiredStrategy;
//登出成功处理逻辑
@Autowired
CustomizeLogoutSuccessHandler logoutSuccessHandler;
@Bean
public UserDetailsService userDetailsService() {
return new UserDetailsServiceImpl();
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public PersistentTokenRepository getPersistentTokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
return jdbcTokenRepository;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(myAuthenticationProvider);
// auth.userDetailsService(userDetailsService());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
// 基于token,所以不需要session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().authorizeRequests().
// 所以请求都需要认证
anyRequest().authenticated().
// 登出
and().logout().logoutUrl("/logout").
permitAll(). // 允许所有用户
logoutSuccessHandler(logoutSuccessHandler). // 登出成功处理逻辑
// deleteCookies("JESSIONID"). // 登出之后删除cookie
// 登入
and().formLogin().loginProcessingUrl("/login").usernameParameter("username").passwordParameter("password").permitAll().
successHandler(authenticationSuccessHandler).failureHandler(authenticationFailureHandler).
// 记住我
and().rememberMe().tokenRepository(getPersistentTokenRepository()).
tokenValiditySeconds(15*60*1000).
// 异常处理(权限拒绝、登录失效等)
and().exceptionHandling().
authenticationEntryPoint(authenticationEntryPoint). // 匿名用户访问无权限资源时的异常处理
// 访问过滤器
and().addFilter(new AuthorizationFilter(authenticationManager())).httpBasic().
// 会话管理
and().sessionManagement().
maximumSessions(1). // 同一账号同时登录最大用户数
expiredSessionStrategy(sessionInformationExpiredStrategy); // 会话失效(账号被挤下线)处理逻辑
// 禁用缓存
http.headers().cacheControl();
}
}
3、自定义用户名密码校验 MyAuthenticationProvider
import com.example.office.utils.AesEncryptUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;
/**
* 自定义用户名密码校验
*/
@Component
public class MyAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 获取用户输入的用户名和密码
String username = authentication.getName();
String password = authentication.getCredentials().toString();
// 登录密码前端加密传输,需先解密
password = AesEncryptUtil.decrypt(password);
// 获取封装用户的信息
UserDetails user = userDetailsService.loadUserByUsername(username);
if (user == null) {
throw new BadCredentialsException("查无此用户");
}
// 进行密码的对比
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
boolean flag = bCryptPasswordEncoder.matches(password, user.getPassword());
// 校验通过
if (flag) {
// 将权限信息也封装进去
return new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
} else {
throw new BadCredentialsException("用户名或密码错误!");
}
}
@Override
public boolean supports(Class<?> authentication) {
return true;
}
}
4、登录成功处理逻辑 CustomizeAuthenticationSuccessHandler
import com.example.office.utils.JsonResult;
import com.example.office.utils.TokenUtil;
import net.minidev.json.JSONValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
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 CustomizeAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private final static Logger log = LoggerFactory.getLogger(CustomizeAuthenticationSuccessHandler.class);