JWT登录认证Springboot详解
作者:十&年
文章主要介绍了如何在Java项目中使用JWT进行用户认证和授权,通过定义一个常量,编写JWT工具类来生成和解析token,登录时在服务端生成token并返回给客户端,客户端使用拦截器拦截请求,验证token的有效性,从而实现权限控制,文章旨在分享个人经验,为开发者提供参考
SystemPara.SECRET 是自己定义的常量
依赖
<!-- token --> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.3.0</version> </dependency>
一、JWT工具类
package com.cn.util; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; import com.cn.util.SystemPara; import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithm; import java.io.UnsupportedEncodingException; import java.security.SignatureException; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * @Author 徐本锡 * @Date 2019/7/4 * @Param * @return **/ public class JWTUtil { private static final long EXPIRE_TIME = 5 * 60 * 1000; public static final String TOKEN_HEADER = "token"; public static final String TOKEN_PREFIX = "xbx_"; /** * @Author 徐本锡 * @Description 生成token * @Date 2019/7/4 * @Param * @return **/ public static String createToken (String logon_name) throws UnsupportedEncodingException { //签名发布时间 Date createTime = new Date(); //设置签名过期时间 5分钟 Calendar nowTime=Calendar.getInstance(); nowTime.add(Calendar.MINUTE,5); Date expiresTime = nowTime.getTime(); //Date expiresTime = new Date(System.currentTimeMillis() + EXPIRE_TIME); Map<String,Object> map=new HashMap<String, Object>(); map.put("alg","HS256");//设置算法 为HS256 map.put("typ","JWT");//设置类型为JWT String token= JWT.create() .withHeader(map) .withClaim("logon_name",logon_name) //可以将基本不重要的对象信息放到claims中 .withIssuedAt(createTime)//设置签发时间 .withExpiresAt(expiresTime)//设置过去时间 过期时间大于签发时间 .sign(Algorithm.HMAC256(SystemPara.SECRET));//用公共密钥加密 return token; } /** * 校验token是否正确 * * @param token 密钥 * @param secret 用户的密码 * @return 是否正确 */ public static boolean verify(String token, String logon_name, String secret) { try { //根据密码生成JWT效验器 Algorithm algorithm = Algorithm.HMAC256(SystemPara.SECRET); JWTVerifier verifier = JWT.require(algorithm) .withClaim("logon_name", logon_name) .build(); //效验TOKEN DecodedJWT jwt = verifier.verify(token); return true; } catch (Exception exception) { return false; } } /** * 获得token中的信息无需secret解密也能获得 * * @return token中包含的用户名 */ public static String getLogonName(String token) { try { DecodedJWT jwt = JWT.decode(token); return jwt.getClaim("logon_name").asString(); } catch (JWTDecodeException e) { return null; } } }
二、登录时生成token
service方法中生成token,然后放入返回结果
//service方法中生成token,然后放入返回结果 String token = JWTUtil.createToken(loginName); resultMap.put("token", token);
controller中 把token放入 response响应中
package com.cn.controller; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.cn.domain.EmpinforVo; import com.cn.service.LogonService; import com.cn.util.JWTUtil; import com.cn.util.R; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletResponse; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author xbx * @date 2019-05-13 */ @RestController @RequestMapping("/Logon") public class LogonController { private final LogonService logonService; @Autowired public LogonController(LogonService logonService) { this.logonService = logonService; } @RequestMapping(value = "", method = RequestMethod.POST) public R logon(HttpServletResponse response, EmpinforVo entity) throws Exception{ Map resultMap = logonService.logon(entity); String token = (String) resultMap.get("token"); //放到响应头部 response.setHeader(JWTUtil.TOKEN_HEADER, JWTUtil.TOKEN_PREFIX + token); return R.success(resultMap); } }
三、创建拦截器
package com.cn.interceptor; import com.cn.util.JWTUtil; import com.cn.util.SystemPara; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * token验证拦截 */ public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 取得token String tokenHeader = request.getHeader(JWTUtil.TOKEN_HEADER); if (tokenHeader == null || "".equals(tokenHeader)) { throw new Exception("token不存在"); } if (!tokenHeader.startsWith(JWTUtil.TOKEN_PREFIX)) { throw new Exception("这是你自己造的token吧"); } String token = tokenHeader.replace(JWTUtil.TOKEN_PREFIX, "");//真正的token String logonName = JWTUtil.getLogonName(token); // 验证token是否有效 if (!JWTUtil.verify(token, logonName, SystemPara.SECRET)){ throw new Exception("token已失效"); } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // TODO Auto-generated method stub } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // TODO Auto-generated method stub } }
四、配置拦截器
package com.cn.config; import com.cn.interceptor.JwtInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * @Author 徐本锡 **/ @Configuration public class WebAppConfiguration implements WebMvcConfigurer { /** * 配置静态资源 */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { String path= "/"; for(int i=1900; i<=2500; i++){ path = String.valueOf(i); registry.addResourceHandler("/"+path+"/**").addResourceLocations("file:C:/"+path+"/"); registry.addResourceHandler("/"+path+"/**").addResourceLocations("file:/"+path+"/"); } } /** * 跨域支持 */ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowCredentials(true) .allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH") .maxAge(3600 * 24); } /** * 添加拦截器 */ @Override public void addInterceptors(InterceptorRegistry registry) { //拦截路径可自行配置多个 可用 ,分隔开 registry.addInterceptor(new JwtInterceptor()).addPathPatterns("/**").excludePathPatterns("/Logon"); } }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。