根据上一章https://blog.csdn.net/he_lei/article/details/115482297
继续扩展,jwt来前后分离
引入pom
<!--生成token-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
首先要用到jwt生成工具
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.codec.binary.Base64;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;
/**
* @description: 描述
* @create: 2019-07-22 11:26
*/
public class JwtUtil {
/**
* token 过期时间, 单位: 秒. 这个值表示 30 天
*/
private static final long TOKEN_EXPIRED_TIME = 30 * 24 * 60 * 60;
/**
* jwt 加密解密密钥, 这里请自行赋值,本人暂且使用随机数16位
*/
private static final String JWT_SECRET = "1AsdadSAS123daXX";
public static final String jwtId = "tokenId";
/**
* 创建JWT
*
* @param claims 这个是payLoad的部分内容, jwt格式:jwtHeader.jwtPayLoad.Signature
*/
public static String createJWT(Map<String, Object> claims, Long time) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; //指定签名的时候使用的签名算法,也就是header那部分,jjwt已经将这部分内容封装好了。
Date now = new Date(System.currentTimeMillis());
SecretKey secretKey = generalKey();
long nowMillis = System.currentTimeMillis();//生成JWT的时间
//下面就是在为payload添加各种标准声明和私有声明了
JwtBuilder builder = Jwts.builder().setClaims(claims) //这里其实就是new一个JwtBuilder,设置jwt的body
.setClaims(claims) //如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
.setHeaderParam("alg", "HS256") //设置header
.signWith(signatureAlgorithm, secretKey);//设置签名使用的签名算法和签名使用的秘钥
if (time >= 0) {
long expMillis = nowMillis + time * 1000;
Date exp = new Date(expMillis);
builder.setExpiration(exp); //设置过期时间
}
return builder.compact();
}
/**
* 验证jwt
*/
public static Claims verifyJwt(String token) {
//签名秘钥,和生成的签名的秘钥一模一样
SecretKey key = generalKey();
Claims claims;
try {
claims = Jwts.parser() //得到DefaultJwtParser
.setSigningKey(key) //设置签名的秘钥
.parseClaimsJws(token).getBody();
} catch (Exception e) {
claims = null;
}//设置需要解析的jwt
return claims;
}
/**
* 由字符串生成加密key
*
* @return
*/
public static SecretKey generalKey() {
String stringKey = JWT_SECRET;
byte[] encodedKey = Base64.decodeBase64(stringKey);
SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "HS256");
return key;
}
/**
* 根据userId和openid生成token
*/
public static String generateToken(String id) {
Map<String, Object> map = new HashMap<>();
map.put("id", id);
map.put("role","a");
return createJWT(map, TOKEN_EXPIRED_TIME);
}
public static String GetgenerateToken(String token) {
return verifyJwt(token).get("id").toString();
}
public static String generateToken(SecurityUserEntity extendUserBean, String name, String authorities) {
Map<String, Object> map = new HashMap<>();
map.put("id",extendUserBean.getId());
map.put("user",extendUserBean);
map.put("name", name);
map.put("role",authorities);
return createJWT(map, TOKEN_EXPIRED_TIME);
}
}
继承OncePerRequestFilter 重写doFilterInternal
package com.helei.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.helei.commons.Resp;
import com.helei.entity.SecurityUserEntity;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@Slf4j
@Component
public class JWTAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String header = request.getHeader("head");
/* if(StringUtils.isBlank(header)){
header = request.getParameter(SecurityConstant.HEADER);
}*/
Boolean notValid = StringUtils.isBlank(header);
if (notValid) {
chain.doFilter(request, response);
return;
}
try {
// UsernamePasswordAuthenticationToken 继承 AbstractAuthenticationToken 实现 Authentication
// 所以当在页面中输入用户名和密码之后首先会进入到 UsernamePasswordAuthenticationToken验证(Authentication),
UsernamePasswordAuthenticationToken authentication = getAuthentication(header, response);
SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (Exception e) {
e.toString();
}
chain.doFilter(request, response);
}
private UsernamePasswordAuthenticationToken getAuthentication(String header, HttpServletResponse response) {
// 用户名
String username = null;
// 权限
// List<GrantedAuthority> authorities = new ArrayList<>();
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
SecurityUserEntity extendUserBean1 = null;
try {
// 解析token
Claims claims = JwtUtil.verifyJwt(header);
logger.info("claims:" + claims);
// 获取用户名
username = claims.get("name").toString();
logger.info("name:" + username);
// 获取权限
String[] roles = claims.get("role").toString().split(",");
for (String s : roles) {
authorities.add(new SimpleGrantedAuthority("ROLE_" + s));
}
// if(!StringUtils.isEmpty(authority)){
// authorities.add(new SimpleGrantedAuthority("ROLE_a"));
// }
} catch (ExpiredJwtException e) {
response.setContentType("application/json;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
PrintWriter out = null;
try {
out = response.getWriter();
out.write(new ObjectMapper().writeValueAsString(Resp.getNew().fail("登录已失效,请重新登录")));
} catch (Exception jsonProcessingException) {
jsonProcessingException.printStackTrace();
}
out.flush();
out.close();
} catch (Exception e) {
log.error(e.toString());
response.setContentType("application/json;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
PrintWriter out = null;
try {
out = response.getWriter();
out.write(new ObjectMapper().writeValueAsString(Resp.getNew().fail("解析token错误")));
} catch (Exception jsonProcessingException) {
jsonProcessingException.printStackTrace();
}
out.flush();
out.close();
}
System.out.println(new Gson().toJson(authorities));
if (StringUtils.isNotBlank(username)) {
// 踩坑提醒 此处password不能为null
UserAuthentication userAuthentication = new UserAuthentication(username, "", authorities);
userAuthentication.setExtendUserBean(extendUserBean1);
// User principal = new User(username, "", authorities);
return new UsernamePasswordAuthenticationToken(userAuthentication, null, authorities);
}
return null;
}
}