package com.alatus.web;
import com.alatus.model.TUser;
import com.alatus.result.R;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
// 获取登录信息
@GetMapping(value = "/api/login/info")
public R loginInfo(Authentication authentication){
TUser tUser = (TUser) authentication.getPrincipal();
return R.OK(tUser);
}
//免登录验证
//因为发送的请求过来首先会过filter那一关,能到这说明token验证都通过了,我们直接返回200即可
@GetMapping(value = "/api/login/free")
public R freeLogin(){
return R.OK();
}
}
package com.alatus.web;
import com.alatus.model.TUser;
import com.alatus.result.R;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
// 获取登录信息
@GetMapping(value = "/api/login/info")
public R loginInfo(Authentication authentication){
TUser tUser = (TUser) authentication.getPrincipal();
return R.OK(tUser);
}
//免登录验证
//因为发送的请求过来首先会过filter那一关,能到这说明token验证都通过了,我们直接返回200即可
@GetMapping(value = "/api/login/free")
public R freeLogin(){
return R.OK();
}
}
package com.alatus.result;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
// 封装web层向前端返回的结果
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class R {
//表示返回的结果码,比如200成功,500失败
private int code;
//表示返回的结果信息,比如 用户登录状态失效了,请求参数格式有误.......
private String msg;
//表示返回的结果数据,数据可能是一个对象,也可以是一个List集合.....
private Object data;
public static R OK() {
return R.builder()
.code(CodeEnum.OK.getCode())
.msg(CodeEnum.OK.getMsg())
.build();
}
public static R OK(int code, String msg) {
return R.builder()
.code(code)
.msg(msg)
.build();
}
public static R OK(Object data) {
return R.builder()
.code(CodeEnum.OK.getCode())
.msg(CodeEnum.OK.getMsg())
.data(data)
.build();
}
public static R OK(CodeEnum codeEnum) {
return R.builder()
.code(CodeEnum.OK.getCode())
.msg(codeEnum.getMsg())
.build();
}
public static R FAIL() {
return R.builder()
.code(CodeEnum.FAIL.getCode())
.msg(CodeEnum.FAIL.getMsg())
.build();
}
public static R FAIL(String msg) {
return R.builder()
.code(CodeEnum.FAIL.getCode())
.msg(msg)
.build();
}
public static R FAIL(CodeEnum codeEnum) {
return R.builder()
.code(codeEnum.getCode())
.msg(codeEnum.getMsg())
.build();
}
}
package com.alatus.result;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
// 封装web层向前端返回的结果
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class R {
//表示返回的结果码,比如200成功,500失败
private int code;
//表示返回的结果信息,比如 用户登录状态失效了,请求参数格式有误.......
private String msg;
//表示返回的结果数据,数据可能是一个对象,也可以是一个List集合.....
private Object data;
public static R OK() {
return R.builder()
.code(CodeEnum.OK.getCode())
.msg(CodeEnum.OK.getMsg())
.build();
}
public static R OK(int code, String msg) {
return R.builder()
.code(code)
.msg(msg)
.build();
}
public static R OK(Object data) {
return R.builder()
.code(CodeEnum.OK.getCode())
.msg(CodeEnum.OK.getMsg())
.data(data)
.build();
}
public static R OK(CodeEnum codeEnum) {
return R.builder()
.code(CodeEnum.OK.getCode())
.msg(codeEnum.getMsg())
.build();
}
public static R FAIL() {
return R.builder()
.code(CodeEnum.FAIL.getCode())
.msg(CodeEnum.FAIL.getMsg())
.build();
}
public static R FAIL(String msg) {
return R.builder()
.code(CodeEnum.FAIL.getCode())
.msg(msg)
.build();
}
public static R FAIL(CodeEnum codeEnum) {
return R.builder()
.code(codeEnum.getCode())
.msg(codeEnum.getMsg())
.build();
}
}
package com.alatus.config;
import com.alatus.config.filter.TokenVerifyFilter;
import com.alatus.config.handler.MyAuthenticationFailureHandler;
import com.alatus.config.handler.MyAuthenticationSuccessHandler;
import com.alatus.config.handler.MyLogoutSuccessHandler;
import com.alatus.constant.Constants;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;
@Configuration
public class SecurityConfig {
@Resource
private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
@Resource
private MyLogoutSuccessHandler myLogoutSuccessHandler;
@Resource
private TokenVerifyFilter tokenVerifyFilter;
// 配置加密器
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Resource
private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity,CorsConfigurationSource configurationSource) throws Exception{
return httpSecurity
.formLogin((formLogin) -> {
formLogin.loginProcessingUrl((Constants.LOGIN_URI))
.usernameParameter("loginAct")
.passwordParameter("loginPwd")
.successHandler(myAuthenticationSuccessHandler)
.failureHandler(myAuthenticationFailureHandler);
})
// SecurityFilterChain改变了默认行为,不再拦截了,需要手动拦截
.authorizeHttpRequests((authorize) -> {
// 对任何请求进行拦截,任何请求都需要登录才可以访问
// /api/login这个请求放开,其他请求正常拦截
authorize.requestMatchers("/api/login").permitAll().anyRequest().authenticated();
})
.csrf((csrf) -> {
//禁用跨站请求伪造
csrf.disable();
})
//支持跨域请求
.cors((cors)->{
cors.configurationSource(configurationSource);
})
.sessionManagement((session) -> {
// 让session的创建策略为不创建
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
})
// 添加我们自定义的filter
.addFilterBefore(tokenVerifyFilter, LogoutFilter.class)
// 退出登录
.logout((logout) -> {
// 退出的地址,这个也不需要我们写controller
logout.logoutUrl("/api/logOut").logoutSuccessHandler(myLogoutSuccessHandler);
})
.build();
}
@Bean
public CorsConfigurationSource configurationSource(){
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedOrigins(Arrays.asList("*"));//允许任意来源
corsConfiguration.setAllowedMethods(Arrays.asList("*"));//允许任意方法请求
corsConfiguration.setAllowedHeaders(Arrays.asList("*"));//允许请求头任意内容
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// 任何路径都按这个来
source.registerCorsConfiguration("/**",corsConfiguration);
return source;
}
}
package com.alatus.config;
import com.alatus.config.filter.TokenVerifyFilter;
import com.alatus.config.handler.MyAuthenticationFailureHandler;
import com.alatus.config.handler.MyAuthenticationSuccessHandler;
import com.alatus.config.handler.MyLogoutSuccessHandler;
import com.alatus.constant.Constants;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;
@Configuration
public class SecurityConfig {
@Resource
private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
@Resource
private MyLogoutSuccessHandler myLogoutSuccessHandler;
@Resource
private TokenVerifyFilter tokenVerifyFilter;
// 配置加密器
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Resource
private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity,CorsConfigurationSource configurationSource) throws Exception{
return httpSecurity
.formLogin((formLogin) -> {
formLogin.loginProcessingUrl((Constants.LOGIN_URI))
.usernameParameter("loginAct")
.passwordParameter("loginPwd")
.successHandler(myAuthenticationSuccessHandler)
.failureHandler(myAuthenticationFailureHandler);
})
// SecurityFilterChain改变了默认行为,不再拦截了,需要手动拦截
.authorizeHttpRequests((authorize) -> {
// 对任何请求进行拦截,任何请求都需要登录才可以访问
// /api/login这个请求放开,其他请求正常拦截
authorize.requestMatchers("/api/login").permitAll().anyRequest().authenticated();
})
.csrf((csrf) -> {
//禁用跨站请求伪造
csrf.disable();
})
//支持跨域请求
.cors((cors)->{
cors.configurationSource(configurationSource);
})
.sessionManagement((session) -> {
// 让session的创建策略为不创建
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
})
// 添加我们自定义的filter
.addFilterBefore(tokenVerifyFilter, LogoutFilter.class)
// 退出登录
.logout((logout) -> {
// 退出的地址,这个也不需要我们写controller
logout.logoutUrl("/api/logOut").logoutSuccessHandler(myLogoutSuccessHandler);
})
.build();
}
@Bean
public CorsConfigurationSource configurationSource(){
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedOrigins(Arrays.asList("*"));//允许任意来源
corsConfiguration.setAllowedMethods(Arrays.asList("*"));//允许任意方法请求
corsConfiguration.setAllowedHeaders(Arrays.asList("*"));//允许请求头任意内容
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// 任何路径都按这个来
source.registerCorsConfiguration("/**",corsConfiguration);
return source;
}
}
package com.alatus.config.handler;
import com.alatus.constant.Constants;
import com.alatus.model.TUser;
import com.alatus.result.CodeEnum;
import com.alatus.result.R;
import com.alatus.service.RedisService;
import com.alatus.util.JSONUtils;
import com.alatus.util.ResponseUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
@Resource
private RedisService redisService;
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//用户退出登录,那么把redis中的jwt删除
TUser tUser = (TUser) authentication.getPrincipal();
// 退出还需要删除redis
redisService.removeValue(Constants.REDIS_JWT_KEY + tUser.getId());
//执行到这里,说明退出成功,那我们向前端返回json就行了
R result = R.OK(CodeEnum.USER_LOG_OUT);
//把R对象转成json
String resultJSON = JSONUtils.toJSON(result);
//把json写出去,写到浏览器
ResponseUtils.write(response, resultJSON);
}
}
package com.alatus.config.handler;
import com.alatus.constant.Constants;
import com.alatus.model.TUser;
import com.alatus.result.CodeEnum;
import com.alatus.result.R;
import com.alatus.service.RedisService;
import com.alatus.util.JSONUtils;
import com.alatus.util.ResponseUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
@Resource
private RedisService redisService;
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//用户退出登录,那么把redis中的jwt删除
TUser tUser = (TUser) authentication.getPrincipal();
// 退出还需要删除redis
redisService.removeValue(Constants.REDIS_JWT_KEY + tUser.getId());
//执行到这里,说明退出成功,那我们向前端返回json就行了
R result = R.OK(CodeEnum.USER_LOG_OUT);
//把R对象转成json
String resultJSON = JSONUtils.toJSON(result);
//把json写出去,写到浏览器
ResponseUtils.write(response, resultJSON);
}
}
package com.alatus.config.handler;
import com.alatus.constant.Constants;
import com.alatus.model.TUser;
import com.alatus.result.R;
import com.alatus.service.RedisService;
import com.alatus.util.JSONUtils;
import com.alatus.util.JWTUtils;
import com.alatus.util.ResponseUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Resource
private RedisService redisService;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//由于禁用了session,我们在登录成功后,需要在服务器保持用户的登录状态,前端下次来访问服务器端的时候,服务器端要知道这个人登录了
//登录成功,执行该方法,在该方法中返回json给前端,就行了
TUser tUser = (TUser) authentication.getPrincipal();
//1、生成jwt
//把tUser对象转成json作为负载数据放入jwt
String userJSON = JSONUtils.toJSON(tUser);
String jwt = JWTUtils.createJWT(userJSON);
//2、写入redis
redisService.setValue(Constants.REDIS_JWT_KEY + tUser.getId(), jwt);
//3、设置jwt的过期时间(如果选择了记住我,过期时间是7天,否则是30分钟)
String rememberMe = request.getParameter("rememberMe");
if (Boolean.parseBoolean(rememberMe)) {
redisService.expire(Constants.REDIS_JWT_KEY + tUser.getId(), Constants.EXPIRE_TIME, TimeUnit.SECONDS);
} else {
redisService.expire(Constants.REDIS_JWT_KEY + tUser.getId(), Constants.DEFAULT_EXPIRE_TIME, TimeUnit.SECONDS);
}
//登录成功的统一结果
R result = R.OK(jwt);
//把R对象转成json
String resultJSON = JSONUtils.toJSON(result);
//把R以json返回给前端
ResponseUtils.write(response, resultJSON);
}
}
package com.alatus.config.handler;
import com.alatus.constant.Constants;
import com.alatus.model.TUser;
import com.alatus.result.R;
import com.alatus.service.RedisService;
import com.alatus.util.JSONUtils;
import com.alatus.util.JWTUtils;
import com.alatus.util.ResponseUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Resource
private RedisService redisService;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//由于禁用了session,我们在登录成功后,需要在服务器保持用户的登录状态,前端下次来访问服务器端的时候,服务器端要知道这个人登录了
//登录成功,执行该方法,在该方法中返回json给前端,就行了
TUser tUser = (TUser) authentication.getPrincipal();
//1、生成jwt
//把tUser对象转成json作为负载数据放入jwt
String userJSON = JSONUtils.toJSON(tUser);
String jwt = JWTUtils.createJWT(userJSON);
//2、写入redis
redisService.setValue(Constants.REDIS_JWT_KEY + tUser.getId(), jwt);
//3、设置jwt的过期时间(如果选择了记住我,过期时间是7天,否则是30分钟)
String rememberMe = request.getParameter("rememberMe");
if (Boolean.parseBoolean(rememberMe)) {
redisService.expire(Constants.REDIS_JWT_KEY + tUser.getId(), Constants.EXPIRE_TIME, TimeUnit.SECONDS);
} else {
redisService.expire(Constants.REDIS_JWT_KEY + tUser.getId(), Constants.DEFAULT_EXPIRE_TIME, TimeUnit.SECONDS);
}
//登录成功的统一结果
R result = R.OK(jwt);
//把R对象转成json
String resultJSON = JSONUtils.toJSON(result);
//把R以json返回给前端
ResponseUtils.write(response, resultJSON);
}
}
package com.alatus.result;
import lombok.*;
@Getter
@NoArgsConstructor
@RequiredArgsConstructor
@AllArgsConstructor
public enum CodeEnum {
OK(200,"成功"),
FAIL(500,"失败"),
TOKEN_IS_EMPTY(901,"请求Token参数为空"),
TOKEN_IS_EXPIRED(902,"Token已过期"),
TOKEN_IS_ERROR(903,"Token有误"),
TOKEN_IS_NONE_MATCH(904,"Token信息不合法"),
USER_LOG_OUT("退出成功");
// 结果码
private int code;
// 结果信息
@NonNull
private String msg;
}
package com.alatus.result;
import lombok.*;
@Getter
@NoArgsConstructor
@RequiredArgsConstructor
@AllArgsConstructor
public enum CodeEnum {
OK(200,"成功"),
FAIL(500,"失败"),
TOKEN_IS_EMPTY(901,"请求Token参数为空"),
TOKEN_IS_EXPIRED(902,"Token已过期"),
TOKEN_IS_ERROR(903,"Token有误"),
TOKEN_IS_NONE_MATCH(904,"Token信息不合法"),
USER_LOG_OUT("退出成功");
// 结果码
private int code;
// 结果信息
@NonNull
private String msg;
}
package com.alatus.config.filter;
import com.alatus.constant.Constants;
import com.alatus.model.TUser;
import com.alatus.result.R;
import com.alatus.service.RedisService;
import com.alatus.util.JSONUtils;
import com.alatus.util.JWTUtils;
import com.alatus.util.ResponseUtils;
import com.alatus.result.CodeEnum;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import static com.alatus.result.CodeEnum.TOKEN_IS_EXPIRED;
@Component
public class TokenVerifyFilter extends OncePerRequestFilter {
@Resource
private RedisService redisService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (request.getRequestURI().equals(Constants.LOGIN_URI)) { //如果是登录请求,此时还没有生成jwt,那不需要对登录请求进行jwt验证
//验证jwt通过了 ,让Filter链继续执行,也就是继续执行下一个Filter
filterChain.doFilter(request, response);
} else {
String token = request.getHeader("Authorization");
if(!StringUtils.hasText("Authorization")){
// 没拿到token,将失败这个枚举传回去,解析并取出常量拼接
R result = R.FAIL(CodeEnum.TOKEN_IS_EMPTY);
// 封装
String resultJSON = JSONUtils.toJSON(result);
// 返回
ResponseUtils.write(response,resultJSON);
return;
}
// 验证token有没有被篡改过,也是验证token合法性
if (!(JWTUtils.verifyJWT(token))){
// token不合法
R result = R.FAIL(CodeEnum.TOKEN_IS_NONE_MATCH);
// 封装
String resultJSON = JSONUtils.toJSON(result);
// 返回
ResponseUtils.write(response,resultJSON);
return;
}
TUser tUser = JWTUtils.parseUserFromJWT(token);
String redisToken = (String) redisService.getValue(Constants.REDIS_JWT_KEY + tUser.getId());
if(!StringUtils.hasText(redisToken)){
// 没有获取到内容说明token过期了
R fail = R.FAIL(TOKEN_IS_EXPIRED);
String json = JSONUtils.toJSON(fail);
ResponseUtils.write(response,json);
return;
}
if (!redisToken.equals(token)) {
// 登陆失败token错误
R result = R.FAIL(CodeEnum.TOKEN_IS_ERROR);
// 把R对象转为JSON
String json = JSONUtils.toJSON(result);
ResponseUtils.write(response,json);
return;
}
// jwt验证通过了
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(tUser,tUser.getLoginPwd(),tUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
// 验证jwt通过了,让filter链继续执行
filterChain.doFilter(request,response);
}
}
}
package com.alatus.config.filter;
import com.alatus.constant.Constants;
import com.alatus.model.TUser;
import com.alatus.result.R;
import com.alatus.service.RedisService;
import com.alatus.util.JSONUtils;
import com.alatus.util.JWTUtils;
import com.alatus.util.ResponseUtils;
import com.alatus.result.CodeEnum;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import static com.alatus.result.CodeEnum.TOKEN_IS_EXPIRED;
@Component
public class TokenVerifyFilter extends OncePerRequestFilter {
@Resource
private RedisService redisService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (request.getRequestURI().equals(Constants.LOGIN_URI)) { //如果是登录请求,此时还没有生成jwt,那不需要对登录请求进行jwt验证
//验证jwt通过了 ,让Filter链继续执行,也就是继续执行下一个Filter
filterChain.doFilter(request, response);
} else {
String token = request.getHeader("Authorization");
if(!StringUtils.hasText("Authorization")){
// 没拿到token,将失败这个枚举传回去,解析并取出常量拼接
R result = R.FAIL(CodeEnum.TOKEN_IS_EMPTY);
// 封装
String resultJSON = JSONUtils.toJSON(result);
// 返回
ResponseUtils.write(response,resultJSON);
return;
}
// 验证token有没有被篡改过,也是验证token合法性
if (!(JWTUtils.verifyJWT(token))){
// token不合法
R result = R.FAIL(CodeEnum.TOKEN_IS_NONE_MATCH);
// 封装
String resultJSON = JSONUtils.toJSON(result);
// 返回
ResponseUtils.write(response,resultJSON);
return;
}
TUser tUser = JWTUtils.parseUserFromJWT(token);
String redisToken = (String) redisService.getValue(Constants.REDIS_JWT_KEY + tUser.getId());
if(!StringUtils.hasText(redisToken)){
// 没有获取到内容说明token过期了
R fail = R.FAIL(TOKEN_IS_EXPIRED);
String json = JSONUtils.toJSON(fail);
ResponseUtils.write(response,json);
return;
}
if (!redisToken.equals(token)) {
// 登陆失败token错误
R result = R.FAIL(CodeEnum.TOKEN_IS_ERROR);
// 把R对象转为JSON
String json = JSONUtils.toJSON(result);
ResponseUtils.write(response,json);
return;
}
// jwt验证通过了
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(tUser,tUser.getLoginPwd(),tUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
// 验证jwt通过了,让filter链继续执行
filterChain.doFilter(request,response);
}
}
}
package com.alatus.util;
import com.alatus.model.TUser;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* jwt工具类
*
*/
public class JWTUtils {
public static final String SECRET = "dY8300olWQ3345;1d<3w48";
/**
* 生成JWT (token)
*
*/
public static String createJWT(String userJSON) {
//组装头数据
Map<String, Object> header = new HashMap<>();
header.put("alg", "HS256");
header.put("typ", "JWT");
return JWT.create()
//头部
.withHeader(header)
//负载
.withClaim("user", userJSON)
//签名
.sign(Algorithm.HMAC256(SECRET));
}
/**
* 验证JWT
*
* @param jwt 要验证的jwt的字符串
*/
public static Boolean verifyJWT(String jwt) {
try {
// 使用秘钥创建一个JWT验证器对象
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
//验证JWT,如果没有抛出异常,说明验证通过,否则验证不通过
jwtVerifier.verify(jwt);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 解析JWT的数据
*
*/
public static void parseJWT(String jwt) {
try {
// 使用秘钥创建一个验证器对象
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
//验证JWT,得到一个解码后的jwt对象
DecodedJWT decodedJWT = jwtVerifier.verify(jwt);
//通过解码后的jwt对象,就可以获取里面的负载数据
Claim nickClaim = decodedJWT.getClaim("nick");
Claim ageClaim = decodedJWT.getClaim("age");
Claim phoneClaim = decodedJWT.getClaim("phone");
Claim birthDayClaim = decodedJWT.getClaim("birthDay");
String nick = nickClaim.asString();
int age = ageClaim.asInt();
String phone = phoneClaim.asString();
Date birthDay = birthDayClaim.asDate();
System.out.println(nick + " -- " + age + " -- " + phone + " -- " + birthDay);
} catch (TokenExpiredException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static TUser parseUserFromJWT(String jwt) {
try {
// 使用秘钥创建一个验证器对象
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
//验证JWT,得到一个解码后的jwt对象
DecodedJWT decodedJWT = jwtVerifier.verify(jwt);
//通过解码后的jwt对象,就可以获取里面的负载数据
Claim userClaim = decodedJWT.getClaim("user");
String userJSON = userClaim.asString();
return JSONUtils.toBean(userJSON, TUser.class);
} catch (TokenExpiredException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
package com.alatus.util;
import com.alatus.model.TUser;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* jwt工具类
*
*/
public class JWTUtils {
public static final String SECRET = "dY8300olWQ3345;1d<3w48";
/**
* 生成JWT (token)
*
*/
public static String createJWT(String userJSON) {
//组装头数据
Map<String, Object> header = new HashMap<>();
header.put("alg", "HS256");
header.put("typ", "JWT");
return JWT.create()
//头部
.withHeader(header)
//负载
.withClaim("user", userJSON)
//签名
.sign(Algorithm.HMAC256(SECRET));
}
/**
* 验证JWT
*
* @param jwt 要验证的jwt的字符串
*/
public static Boolean verifyJWT(String jwt) {
try {
// 使用秘钥创建一个JWT验证器对象
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
//验证JWT,如果没有抛出异常,说明验证通过,否则验证不通过
jwtVerifier.verify(jwt);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 解析JWT的数据
*
*/
public static void parseJWT(String jwt) {
try {
// 使用秘钥创建一个验证器对象
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
//验证JWT,得到一个解码后的jwt对象
DecodedJWT decodedJWT = jwtVerifier.verify(jwt);
//通过解码后的jwt对象,就可以获取里面的负载数据
Claim nickClaim = decodedJWT.getClaim("nick");
Claim ageClaim = decodedJWT.getClaim("age");
Claim phoneClaim = decodedJWT.getClaim("phone");
Claim birthDayClaim = decodedJWT.getClaim("birthDay");
String nick = nickClaim.asString();
int age = ageClaim.asInt();
String phone = phoneClaim.asString();
Date birthDay = birthDayClaim.asDate();
System.out.println(nick + " -- " + age + " -- " + phone + " -- " + birthDay);
} catch (TokenExpiredException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static TUser parseUserFromJWT(String jwt) {
try {
// 使用秘钥创建一个验证器对象
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
//验证JWT,得到一个解码后的jwt对象
DecodedJWT decodedJWT = jwtVerifier.verify(jwt);
//通过解码后的jwt对象,就可以获取里面的负载数据
Claim userClaim = decodedJWT.getClaim("user");
String userJSON = userClaim.asString();
return JSONUtils.toBean(userJSON, TUser.class);
} catch (TokenExpiredException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
package com.alatus.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JSONUtils {
//jackson这个jar包转json
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
/**
* 把java对象转成json
*
* @param object
* @return
*/
public static String toJSON(Object object) {
try {
//把java对象转成json
return OBJECT_MAPPER.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
/**
* 把json字符串转java对象
*
* @param json
* @param clazz
* @return
* @param <T>
*/
public static <T> T toBean(String json, Class<T> clazz) {
try {
return OBJECT_MAPPER.readValue(json, clazz);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
}
package com.alatus.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JSONUtils {
//jackson这个jar包转json
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
/**
* 把java对象转成json
*
* @param object
* @return
*/
public static String toJSON(Object object) {
try {
//把java对象转成json
return OBJECT_MAPPER.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
/**
* 把json字符串转java对象
*
* @param json
* @param clazz
* @return
* @param <T>
*/
public static <T> T toBean(String json, Class<T> clazz) {
try {
return OBJECT_MAPPER.readValue(json, clazz);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
}