<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.0</version>
</dependency>
import lombok.Data;
/**
* @author fengrz
*/
@Data
public class TokenUser {
String userId;
String userName;
}
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import org.springframework.beans.factory.annotation.Value;
import java.util.Date;
public interface IJavaWebTokenService {
/**
* 根据用户名称生成签名
* @param userId
* @param userName
* @return token
*/
String sign(String userId,String userName) throws Exception;
/**
* 签名验证
* @param userId
* @param token
* @return true or false
*/
TokenUser verify(String userId,String token) throws Exception;
}
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.goldnurse.commons.security.IJavaWebTokenService;
import com.goldnurse.commons.security.TokenUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.text.SimpleDateFormat;
import java.util.Date;
@Slf4j
@Service
public class JavaWebTokenServiceImpl implements IJavaWebTokenService {
/**
* 过期时间
*/
@Value("${goldnurse.commons.config.jwt.expire-time}")
private long expireTime;
/**
* token 加密串
*/
@Value("${goldnurse.commons.config.jwt.token-secret}")
private String tokenSecret;
/**
* 根据用户名称生成签名
* @param userId
* @param userName
* @return token
*/
@Override
public String sign(String userId,String userName){
if(StringUtils.isEmpty(userId)){
log.error(" userId is null ");
return null;
}
if(StringUtils.isEmpty(userName)){
log.error(" userName is null ");
return null;
}
long eTime = expireTime*24*60*60*1000L;
String token = null;
try {
Date expiresAt = new Date(System.currentTimeMillis() + eTime);
token = JWT.create()
.withIssuer(userId)
.withClaim("username", userName)
.withExpiresAt(expiresAt)
// 使用了HMAC256加密算法。
.sign(Algorithm.HMAC256(tokenSecret));
} catch (Exception e){
e.printStackTrace();
}
return token;
}
/**
* 签名验证
* @param userId
* @param token
* @return true or false
*/
@Override
public TokenUser verify(String userId, String token) throws Exception{
if(StringUtils.isEmpty(userId)){
log.error(" userId is null ");
return null;
}
if(StringUtils.isEmpty(token)){
log.error(" token is null ");
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(tokenSecret)).withIssuer(userId).build();
DecodedJWT jwt = verifier.verify(token);
TokenUser tokenUser = new TokenUser();
tokenUser.setUserId(userId);
tokenUser.setUserName(jwt.getClaim("username").asString());
log.debug("认证通过:"+jwt.getIssuer()+" - "+ jwt.getClaim("username").asString() + " - " + sdf.format(jwt.getExpiresAt()));
return tokenUser;
} catch (Exception e){
e.printStackTrace();
throw e;
}
}
}
goldnurse:
commons:
config:
jwt:
expire-time: 20 # day
token-secret: 9838383838383838383838
excluded-urls: /survey/user/login,/survey/user/getAll
当controller 方法需要tokenUserId,tokenUserName 时,赋值
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
@Slf4j
public class TokenRequestWrapper extends HttpServletRequestWrapper {
private TokenUser tokenUser;
public TokenRequestWrapper(HttpServletRequest request){
super(request);
}
public TokenRequestWrapper(HttpServletRequest request,TokenUser tokenUser1){
super(request);
tokenUser = tokenUser1;
}
@Override
public String[] getParameterValues(String name) {
if ("tokenUserName".equals(name)){
return new String[]{tokenUser.getUserName()};
}
if ("tokenUserId".equals(name)){
return new String[]{tokenUser.getUserId()};
}
return super.getParameterValues(name);
}
}
import com.goldnurse.commons.security.IJavaWebTokenService;
import com.goldnurse.commons.security.TokenRequestWrapper;
import com.goldnurse.commons.security.TokenUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@WebFilter(urlPatterns = "/*",filterName = "tokenFilter")
public class TokenFilter implements Filter {
@Value("${goldnurse.commons.config.jwt.excluded-urls}")
private String excludedUrls;
@Resource
IJavaWebTokenService iJavaWebTokenService;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if(!check(request.getRequestURL().toString())) {
String userId = request.getHeader("userId");
String token = request.getHeader("token");
if(StringUtils.isEmpty(userId)){
log.error("Token 验证,参数 userId 不允许为空 ");
return;
}
if(StringUtils.isEmpty(token)){
log.error("Token 验证,参数 token 不允许为空");
return;
}
TokenUser tokenUser = null;
try {
tokenUser = iJavaWebTokenService.verify(userId, token);
if (tokenUser != null) {
filterChain.doFilter(new TokenRequestWrapper(request, tokenUser), response);
}
} catch (Exception e) {
log.error("Token 验证失败,请检查是否正确");
return;
}
}else{
filterChain.doFilter(request,response);
}
}
@Override
public void destroy() {
}
/**
* 检查url 是否需要做token验证
* @param url
* @return 需要时,返回 true
*/
public boolean check(String url){
if(excludedUrls == ""){
log.debug("goldnurse.commons.config.jwt.excluded-urls - is null");
}else {
String[] urls = excludedUrls.split(",");
for (String eurl: urls) {
if(url.contains(eurl)){
return true;
}
}
}
return false;
}
}
goldnurse:
commons:
config:
jwt:
expire-time: 20 # day
token-secret: 9999999999
excluded-urls: /survey/user/login,/survey/user/getAll
在SpringBootApplication上使用@ServletComponentScan注解后,Servlet、Filter、Listener可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册,无需其他代码。
@EnableTransactionManagement
@SpringBootApplication
@EnableAsync
@ServletComponentScan
public class SurveyWebApplication {
public static void main(String[] args) {
SpringApplication.run(SurveyWebApplication.class, args);
}
}
如果方法体中需要token 解析出来的tokenUserId,tokenUserName ,只需在方法参数上增加
String tokenUserId,String tokenUserName
@PostMapping(name = "测试",path = "/test")
public String test(String name, String email,String tokenUserId,String tokenUserName) {
log.debug(tokenUserId +" "+ tokenUserName);
return "error";
}