#JWT生成JsonWebToken登录令牌并使用自定义过滤器验证(包含跨域设置)
使用jwt生成jsonwebtoken 并且在自定义过滤器中进行登陆验证实现步骤如下:
1、Maven环境下引入jjwt包。
<!-- jwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.6.0</version>
</dependency>
2、创建配置文件webtoken.properties并设置JWT相关信息。
expiresSecond=15
salt=ikingtech
name=faultapiuser
expiresSecond表示超时时间,单位“天”。
salt可以是一个base64位的签名,用以区别发行人。
name表示发行人名称。
3、创建实体类用以获取配置信息。
import org.springframework.stereotype.Component;
/**
* 加载jwt配置文件类
* @author hufx
* @version 1.0
* @date 2017年1月22日上午11:44:33
*/
@Component
public class WebToken {
private String salt; //base64位签名
private String name; //发行人名称
private int expiresSecond; //保存时间
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getExpiresSecond() {
return expiresSecond;
}
public void setExpiresSecond(int expiresSecond) {
this.expiresSecond = expiresSecond;
}
@Override
public String toString() {
return "WebToken [salt=" + salt + ", name=" + name + ", expiresSecond=" + expiresSecond + "]";
}
}
4、创建工具类生成及解析token值。
@SuppressWarnings("deprecation")
@Component
public class FaultUtil {
private static Logger log = LoggerFactory.getLogger(FaultUtil.class);
private static WebToken webToken = new WebToken();
static {
try {
Resource resource = new ClassPathResource("/webtoken.properties");
Properties Props = PropertiesLoaderUtils.loadProperties(resource);
webToken.setExpiresSecond(Props.getProperty("expiresSecond") == null ? 6379
: Integer.parseInt(Props.getProperty("expiresSecond")));
webToken.setName(Props.getProperty("name"));
webToken.setSalt(Props.getProperty("salt"));
} catch (IOException e) {
log.error("获取 WebTokenProps : " + e);
}
}
/**
* @desc 生成一个token值
* @param key
* @param obj
* @return
*/
public static String getWebToken(String key, Object obj) {
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
// 生成签名密钥
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(webToken.getSalt());
Key signingKey = new SecretKeySpec(apiKeySecretBytes, SignatureAlgorithm.HS256.getJcaName());
// 添加构成JWT的参数
JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT").claim(key, obj).setIssuer(webToken.getName())
.signWith(SignatureAlgorithm.HS256, signingKey);
// 添加Token过期时间
long TTLMillis = webToken.getExpiresSecond() * 24 * 60 * 60 * 1000;
if (TTLMillis >= 0) {
long expMillis = nowMillis + TTLMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp).setNotBefore(now);
}
// 生成JWT
return builder.compact();
}
/**
* @desc 解析token值
* @param jsonWebToken
* @param base64Security
* @return
*/
@SuppressWarnings("unchecked")
public static Map<String, Object> parseWebToken(String jsonWebToken, String key) {
try {
Claims claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(webToken.getSalt()))
.parseClaimsJws(jsonWebToken).getBody();
Map<String, Object> res = (Map<String, Object>) claims.get(key);
return res;
} catch (Exception ex) {
log.error("解析token值:" + ex);
}
return null;
}
/**
* 获取webtoken的失效时间
*
* @param jsonWebToken
* @param key
* @return
* @date 2017年7月10日 上午11:52:52
*/
public static Long getWebTokenTime(String jsonWebToken, String key) {
try {
Claims claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(webToken.getSalt()))
.parseClaimsJws(jsonWebToken).getBody();
return claims.getExpiration().getTime();
} catch (Exception ex) {
log.error("解析token值:" + ex);
}
return null;
}
/**
* 获取当前登录的用户对象
* HttpUserInfoRes
* @author hufx
* @date 2017年8月15日上午11:53:35
*/
public static HttpUserInfoRes getUserByWebToken(HttpServletRequest request) {
try {
String jsonWebToken = request.getHeader("token");
if (jsonWebToken == null) {
return null;
}
Map<String, Object> tUserMap = (Map<String, Object>)parseWebToken(jsonWebToken, "tUser");
if (tUserMap == null) {
return null;
}
//获取当前登录用户时可返回此对象
//HttpUserInfoRes user = new HttpUserInfoRes();
//user.setfId((String) tUserMap.get("fId"));
//user.setfLoginName((String) tUserMap.get("fLoginName"));
//user.setfEmployeeId((String) tUserMap.get("fEmployeeId"));
//user.setfRegisterTime(new Date((long)tUserMap.get("fRegisterTime")));
//user.setfLastLoginIp((String) tUserMap.get("fLastLoginIp"));
//user.setfLastLoginTime(new Date((long)tUserMap.get("fLastLoginTime")));
//user.setfLoginCount((Integer) tUserMap.get("fLoginCount"));
//user.setfUserName((String) tUserMap.get("fUserName"));
//return user;
} catch (Exception e) {
return null;
}
}
}
5、登录成功之后生成并返回token值。
登录校验成功之后生成token值并返回此值,之后每次前端将此token值放进请求头中即可。tUser表示用户对象,可根据实际需要添加。
// HttpUserInfoRes tUserRes = new HttpUserInfoRes(); // 封装返回对象
// tUserRes.setfId(tUser.getfId());
// tUserRes.setfLoginName(tUser.getfLoginName());
// tUserRes.setfEmployeeId(tUser.getfEmployeeId());
// tUserRes.setfRegisterTime(tUser.getfRegisterTime());
// tUserRes.setfLastLoginIp(tUser.getfLastLoginIp());
// tUserRes.setfLoginCount(tUser.getfLoginCount());
// tUserRes.setfLastLoginTime(tUser.getfLastLoginTime());
// tUserRes.setfUserName(tEmployee.getfUserName());
// String accessToken = FaultUtil.getWebToken("tUser", tUserRes); // 登录成功,生成webtoken
// tUserRes.setWebtoken(accessToken);
HttpUserInfoRes继承tUser对象并包含属性:
private String webtoken;// token
private String fUserName;// 用户名称
tUser对象属性:
private String fId;// 账号id
private String fLoginName;// 账号
private String fPassword;// 密码
private String fEmployeeId;// 使用人id
private Date fRegisterTime;// 注册时间
private String fLastLoginIp;// 上次登录ip
private Date fLastLoginTime;// 上次登陆时间
private Integer fLoginCount;// 登陆次数
private Boolean fIsEnable;// 是否可用
private Boolean fIsDelete;// 是否删除
6、添加过滤器进行token验证。
添加如下配置:
import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.iking.fault.filter.HTTPBearerAuthorizeAttribute;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean jwtFilterRegistrationBean(){
//拦截器
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
//自定义拦截类
HTTPBearerAuthorizeAttribute httpBearerFilter = new HTTPBearerAuthorizeAttribute();
registrationBean.setFilter(httpBearerFilter);
List<String> urlPatterns = new ArrayList<String>();
urlPatterns.add("/*");
registrationBean.setUrlPatterns(urlPatterns);
return registrationBean;
}
}
创建自定义过滤器类并进行过滤配置(包含跨域设置):
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.httpclient.HttpStatus;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.iking.fault.model.Msg;
import com.iking.fault.util.FaultUtil;
/**
* 请求过滤类
*
* @author hufx
* @version 1.0
* @date 2017年1月22日下午3:33:01
*
* <br/>
* 备注:从请求header中获取token时的key值约定为 “webtoken”,类型为String
*/
public class HTTPBearerAuthorizeAttribute implements Filter {
private static List<String> releaseList = new ArrayList<String>(); // 放行接口列表
static {
releaseList.add("/user/login"); // pc登录
releaseList.add("/home"); //主页
releaseList.add("/qlOutfieldMonitoring/export"); //飞行状态更新导出
releaseList.add("/pageoffice/"); //pageoffice/
releaseList.add("/faultfile/"); //文件
}
private static List<String> accessTokenKeyList = new ArrayList<String>();// webtokenkey列表
static {
accessTokenKeyList.add("tUser"); // pc
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, filterConfig.getServletContext());
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws JsonProcessingException, IOException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setCharacterEncoding("UTF-8");
httpResponse.setContentType("application/json; charset=utf-8");
httpResponse.setHeader("Access-Control-Allow-Origin", "*");
if("OPTIONS".equals(httpRequest.getMethod())) {
httpResponse.setStatus(HttpStatus.SC_NO_CONTENT); //HttpStatus.SC_NO_CONTENT = 204
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, x-requested-with, Token");
httpResponse.setHeader("Access-Control-Allow-Methods", "OPTIONS,GET,POST,DELETE,PUT");
}
ObjectMapper mapper = new ObjectMapper();
String webtoken = httpRequest.getHeader("token"); // 从请求header中拿出webtoken
String thisUrl = httpRequest.getRequestURL().toString();
try {
//登录和测试接口放行,其余接口全部监听
// if (webtoken == null) { // 测试时 webtoken校验放行 swagger-ui
// chain.doFilter(request, response);
// return;
// }
for (String url : HTTPBearerAuthorizeAttribute.releaseList) { // 验证放行接口
if (thisUrl.indexOf(url) > 0) {
chain.doFilter(request, response);
return;
}
}
if (webtoken != null && webtoken.length() > 7) { // 校验token值
for (String key : accessTokenKeyList) {
Map<String, Object> tUserMap = (Map<String, Object>) FaultUtil.parseWebToken(webtoken, key);
if (tUserMap != null) {
chain.doFilter(request, response);
return;
}
}
}
} catch (Exception e) {
}
//Msg msg = new Msg();
//msg.setSuccess(false);
//msg.setMsg("未登录或登录超时!");
//httpResponse.getWriter().write(mapper.writeValueAsString(msg));
return;
}
@Override
public void destroy() {
}
}
7、前端设置。
前端页面登录成功后拿到token值,首先要将其存在本地,localStorage或者sessionStorage皆可。然后添加前端的拦截器,在每次请求之前将此token值放入request对象的header中即可(此处以Vue-Axios为例):
// 添加webtoken
Axios.interceptors.request.use(function (config) {
// 在请求发出之前进行一些操作
if (localStorage.webtoken) {
config.headers = {
'token': localStorage.webtoken
}
}
return config
}, function (err) {
// Do something with request error
})
至此,一个跨域的JWT登录验证功能完成了。如有疑问烦请@笔者:Q:980420579 Q群:697819474