引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
配置
# JWT配置
jwt:
header: Authorization
secret: qiangesoft
expire: 70000
JWT工具类
package com.qiangesoft.security.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* JWT工具类
*
* @author qiangesoft
* @date 2024-05-14
*/
@Data
@Component
@ConfigurationProperties(prefix = "jwt")
public class JwtUtil {
/**
* 请求头名称
*/
private String header;
/**
* 密钥
*/
private String secret;
/**
* 有效期
*/
private long expire;
/**
* 生成JWT
*
* @param username
* @return
*/
public String generateToken(String username) {
Date nowDate = new Date();
Date expireDate = new Date(nowDate.getTime() + expire * 24 * 60 * 1000);
return Jwts.builder()
.setHeaderParam("typ", "JWT")
.setSubject(username)
.setIssuedAt(nowDate)
.setExpiration(expireDate)
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
/**
* 解析JWT
*
* @param jwt
* @return
*/
public Claims getClaimsByToken(String jwt) {
try {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(jwt)
.getBody();
} catch (Exception e) {
return null;
}
}
/**
* 判断JWT是否过期
*
* @param claims
* @return
*/
public boolean isTokenExpired(Claims claims) {
return claims.getExpiration().before(new Date());
}
}
配置类
package com.qiangesoft.security.config;
import com.qiangesoft.security.access.CustomAccessDeniedHandler;
import com.qiangesoft.security.filter.CaptchaFilter;
import com.qiangesoft.security.filter.TokenFilter;
import com.qiangesoft.security.handler.CustomAuthenticationFailHandler;
import com.qiangesoft.security.handler.CustomAuthenticationSuccessHandler;
import com.qiangesoft.security.handler.CustomLogoutSuccessHandler;
import com.qiangesoft.security.point.CustomAuthenticationEntryPoint;
import com.qiangesoft.security.service.CustomUserDetailsService;
import com.qiangesoft.security.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
* 配置类
*
* @author qiangesoft
* @date 2024-05-14
*/
@EnableWebSecurity
// 开启方法级安全验证
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
@Autowired
private CustomAuthenticationFailHandler customAuthenticationFailHandler;
@Autowired
private CustomLogoutSuccessHandler customLogoutSuccessHandler;
@Autowired
private CustomAccessDeniedHandler customAccessDeniedHandler;
@Autowired
private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
@Autowired
private CaptchaFilter captchaFilter;
@Autowired
private JwtUtil jwtUtil;
@Bean
protected UserDetailsService userDetailsService() {
return new CustomUserDetailsService();
}
@Bean
public TokenFilter tokenFilter() throws Exception {
return new TokenFilter(authenticationManager(), userDetailsService(), jwtUtil);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService())
.passwordEncoder(passwordEncoder());
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// 禁用csrf
.csrf().disable()
// 禁用session
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
// 接口授权
.and()
.authorizeRequests()
.antMatchers(
HttpMethod.GET,
"/",
"/captcha",
"/static/**",
"/templates/**",
"/favicon.ico"
).permitAll()
.antMatchers(HttpMethod.POST, "/login").permitAll()
.anyRequest().authenticated()
// 登录逻辑
.and()
.formLogin()
.successHandler(customAuthenticationSuccessHandler)
.failureHandler(customAuthenticationFailHandler)
// 退出逻辑
.and()
.logout()
.logoutSuccessHandler(customLogoutSuccessHandler)
// 验证账号密码之前执行
.and()
.addFilter(tokenFilter())
.addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class)
// 异常处理器
.exceptionHandling()
.authenticationEntryPoint(customAuthenticationEntryPoint)
.accessDeniedHandler(customAccessDeniedHandler)
// 禁用缓存
.and()
.headers().cacheControl();
}
}
源码地址
码云:https://gitee.com/qiangesoft/boot-business/tree/master/boot-business-security