为什么要使用JWT?实战项目怎么应用?

传统Java项目基于session的登录,以及授权校验

缺点/问题:
1. 服务端保存了登录用户信息(用户量大,存储压力大,还要考虑分布式存储问题)
2. 服务端如未持久化用户登录session信息,每次服务端系统发布 ,登录用户都需要重新登录

那么JWT完美解决以上问题,常用于中大型互联网项目。

原因:JWT在服务端压根不存储登录用户的信息,完全采用算法校验这个token

 

什么是JWT?以及原理,这种大家百度,和b站视频去学习,本章只讲实战项目应用

比如:https://blog.csdn.net/IBLiplus/article/details/82758881

视频:【编程不良人】JWT认证原理、流程整合springboot实战应用,前后端分离认证的解决方案!_哔哩哔哩_bilibili

我们项目代码:

springMvc登录接口:

// 平台登录接口
    @RequestMapping("/login")
    @ApiOperation("登录验证接口")
    public  String login(HttpServletRequest request,HttpServletResponse response) {
        try {
            String loginName = request.getParameter("loginName");
            String password = request.getParameter("password");
            String checkPhoneCode = request.getParameter("checkPhoneCode");  //验证码

//            if(StringUtil.isEmpty(loginName) || StringUtil.isEmpty(password) || StringUtil.isEmpty(checkPhoneCode)){
//                return "帐号或密码或者验证码不能为空!";
//            }
            if(StringUtil.isEmpty(loginName) || StringUtil.isEmpty(password)){
                return "帐号或密码不能为空!";
            }

            CrmUserInfo crmUserInfo = crmUserInfoService.getCustomerInfoByLoginName(loginName);

            if(crmUserInfo == null){
                return "帐号不存在!";
            }else{
                if(!password.equals(crmUserInfo.getPassword())){
                    return "密码错误";
                }
            }

            SessionCrmUserInfo sessionCrmUserInfo = new SessionCrmUserInfo();
            sessionCrmUserInfo.setId(crmUserInfo.getId());
            sessionCrmUserInfo.setOrgId(crmUserInfo.getOrgId());
            sessionCrmUserInfo.setUsername(crmUserInfo.getUsername());
            sessionCrmUserInfo.setPersonImgUrl(crmUserInfo.getPersonImgUrl());
            sessionCrmUserInfo.setName(crmUserInfo.getName());
            sessionCrmUserInfo.setSex(crmUserInfo.getSex());
            sessionCrmUserInfo.setCardId(crmUserInfo.getCardId());
            sessionCrmUserInfo.setAge(crmUserInfo.getAge());
            sessionCrmUserInfo.setPhoneNumber(crmUserInfo.getPhoneNumber());
            sessionCrmUserInfo.setPosition(crmUserInfo.getPosition());
            sessionCrmUserInfo.setBirthDate(crmUserInfo.getBirthDate());
            sessionCrmUserInfo.setOrgName(crmUserInfo.getOrgName());
            sessionCrmUserInfo.setSystemName(crmUserInfo.getSystemName());
            /*  以前的登录方式基于session

            // 把登陆的用户信息放到session里面去
            WebMainUtil.setSessionUserInfo(sessionCrmUserInfo);
            // userId传到cookie里面需要经过des加密,然后用户访问所有url的时候需要加密这个userId去核对
            WebMainUtil.setSessionUserId(loginName);
            //CookieUtil.setCookie(request, response,SessionAttributeName.USER_ID, AESUtil.encrypt(loginName,CookieUtil.userIdPassw), 1);
            CookieUtil.setCookie(request, response, SessionAttributeName.USER_ID, loginName, 1);

           */
            //生成token,存到cookie
            HashMap<String, String> map = new HashMap<String, String>();
            map.put(JWTUtils.Token_name_key, JSON.toJSONString(sessionCrmUserInfo));
            String token = JWTUtils.getToken(map);
            CookieUtil.saveCookie(response,JWTUtils.Token_name_cookie,token,JWTUtils.Cookie_path);  //设置成全局可用的cookie

            return "success";
        } catch (Exception e) {
            e.printStackTrace();
            LOG.error(e.getMessage());
            return "服务异常";
        }
    }

登录之后,拦截每个请求校验,拦截器:


@Component
@Slf4j
public class TokenInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("---------进入登录验证拦截器-------------");
        String token = CookieUtil.getCookie(request, JWTUtils.Token_name_cookie);
        System.out.println("url:" + request.getRequestURL());
        if (StringUtil.isEmpty(token)) {
            System.out.println("token为空");
            response.sendRedirect("/login-view");
            return false;
        } else {
            try {
                JWTUtils.verify(token);
                System.out.println("token验证通过");
            } catch (Exception e) {
                System.out.println("token验证失败");
                CookieUtil.deleteCookie(request, response, "token");
                response.sendRedirect("/login-view");
                return false;
            }
        }
        return true;
    }
}

拦截器配置类:


@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry){
        //项目的 根目录和test 指定重跳转到/login(如果webapp下面有了index.html则下面不生效)
       /* registry.addViewController("/").setViewName("redirect:/login");
        registry.addViewController("/test").setViewName("redirect:/login");
*/
        //把跟目录跳转到login-view 注释的话,默认跳转根目录的index.html
       // registry.addViewController("/").setViewName("redirect:/login-view");

        //把login-view跳转到 试图login(login加上前缀后缀(application.propertise配置的mvc)
        // 这样就跳转到了 /WEB-INF/viewsJsp/login.jsp
        registry.addViewController("/login-view").setViewName("../static/start/login.html");
    }

    //登录拦截器JWT
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new TokenInterceptor())
                .addPathPatterns("/**") //拦截所有请求
                .excludePathPatterns("/"
                        ,"/appResource/**"
                        ,"/assets/**"
                        ,"/h5/**"
                        ,"/start/**"
                        ,"/staticFile/**"
                        ,"/templ/**"
                        ,"/favicon.ico"
                        ,"/index.html"
                        ,"/MP_verify_m9OeemkWw7iC1UNd.txt"
                        ,"/*.css"
                        ,"/index.html"
                        ,"/login/**"
                        ,"/login-view"); //放行静态资源
    }
}

从token里面获取该登录用户的信息:

public static SessionCrmUserInfo getSessionUserInfo(){
		HttpServletRequest request = ((ServletRequestAttributes)
				(RequestContextHolder.currentRequestAttributes())).getRequest();

		String token = CookieUtil.getCookie(request,JWTUtils.Token_name_cookie);

		try {
			String json = (String) JWTUtils.getTokenInfo(token).get(JWTUtils.Token_name_key);
			SessionCrmUserInfo sessionCrmUserInfo  = JSON.parseObject(json,SessionCrmUserInfo.class);

			return sessionCrmUserInfo;
		}/*catch (SignatureVerificationException e){
			e.printStackTrace();
			System.out.println("无效前面");
		}catch (TokenExpiredException e){
			e.printStackTrace();
			System.out.println("token过期");
		}catch (AlgorithmMismatchException e){
			e.printStackTrace();
			System.out.println("token算法不一致");
		}*/catch (Exception e){
			e.printStackTrace();
			System.out.println("token异常"+e.getMessage());
			return null;
		}

		/*
		以前的:
		Object session = getSession().getAttribute(SessionAttributeName.USER_INFO);
		if(session == null){
			return null;
		}else{
			return (SessionCrmUserInfo)session;
		}*/
	}

Jwt核心处理类:


public class JWTUtils {
    //private static final String SignStr = UUID.randomUUID().toString();//如果每次生成新的uuid,意味着每次系统发布,所有用户必须重新登录
    private static final String SignStr = "43wfdgarehetyjutaaaabbbbbbccccc";

    public static final String Token_name_cookie = "login_token";

    public static final String Token_name_key = "userInfo";

    public static final String Cookie_path = "/";

//    private static final String algorithmType = SignatureAlgorithm.HS256.toString();




    /**
     * 生成token  map是登陆个人信息
     * @param map
     * @return
     */
    public static String getToken(Map<String,String> map) throws NoSuchAlgorithmException, InvalidKeyException {
//        Calendar calendar = Calendar.getInstance();
//        calendar.add(Calendar.DATE,3);//7天有效期
//        JWTCreator.Builder builder = JWT.create();
//        map.forEach((k,v) -> {
//            builder.withClaim(k,v);
//        });
//        String token = builder.withExpiresAt(calendar.getTime())
//                .sign(Algorithm.HMAC256(SignStr));


        SecretKey key = Keys.hmacShaKeyFor(SignStr.getBytes(StandardCharsets.UTF_8));  //生成秘钥
        String token = Jwts.builder()
                        .setExpiration(DateUtils.addDays(new Date(),7))  //有效时间7天
                        .setNotBefore(new Date())  //生效时间
                        .setIssuedAt(new Date())  //签发时间
                        .setClaims(map)   //用户登录信息
                        .signWith(key,SignatureAlgorithm.HS256)  //签名
                        .compressWith(CompressionCodecs.DEFLATE)
                        .compact();


        System.out.println("生成token: " + token);
        return token;
    }

    /**
     * 验证token的合法性
     * @param token
     */
    public static void verify(String token){
        SecretKey key = Keys.hmacShaKeyFor(SignStr.getBytes(StandardCharsets.UTF_8));  //生成秘钥

        Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();

    }

    /**
     * 获取tokend里面的个人信息
     * @param token
     * @return
     */
    public static Claims getTokenInfo(String token){
        if(StringUtils.isEmpty(token)){
            return null;
        }else {
            SecretKey key = Keys.hmacShaKeyFor(SignStr.getBytes(StandardCharsets.UTF_8));  //生成秘钥
            return  Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
        }
    }

Cookie的工具类:


/**
 * 使用cookie实现浏览历史记录 
 * @author shengfukang
 * @createDate:2014-11-19
 */
public class CookieUtil {  
	private static Logger logger = LogManager.getLogger();
	public static final String OVERTIME_COOKIE = "_overtime_cookie";
	public static final long OVERTIME_COOKIE_VALUE = 5*60*1000;
	public static final String userIdPassw = "sdfsdfssdfd2";
    /** 
     * Cookie的名字 
     */  
    public static final String COOKIE_HISTORYID = "cookies_history";  
    /** 
     * Cookie的存活时间 
     */  
    public static final int COOKIE_LIFE_TIME = 14 * 24 * 60 * 60;  
    /** 
     * 最大的浏览历史记录条数 
     */  
    public static final int HISTORY_COUNT = 5;  
  
    
    public boolean isOverTimeCookie(HttpServletRequest request, HttpServletResponse response) {
		// TODO Auto-generated method stub
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date now = new Date();
		String last = getCookie(request,CookieUtil.OVERTIME_COOKIE);
		if (!StringUtil.isEmpty(last)) {
			try {
				Date lastTime = sdf.parse(last);
				if((now.getTime()-lastTime.getTime())> CookieUtil.OVERTIME_COOKIE_VALUE){
					//超时
					//setCookie(response, null, SessionAttributeName.USER_ID, null,0);
//					CookieUtils.setCookie(response, null, StockOptionConstants.OVERTIME_COOKIE, null,0);
					//setCookie(response, ContextHolder.getRootPath(), ContextHolder.CFG_SID, null,0);
					return true;
				}else{
					//未超时
					//setCookie(response, null, CookieUtil.OVERTIME_COOKIE,sdf.format(now));
					return false;
				}
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				logger.error(e.getMessage());
				return false;
			}
		} else {
			//首次登陆,不做超时
			//setCookie(response, null, CookieUtil.OVERTIME_COOKIE,sdf.format(now));
			return false;
		}
	}
    
    /** 
     * 获得指定cookie中的值 
     *  
     * @param request 
     * @param cookieName 
     *            要查找的cookie的名字 
     * @return 返回指定Cookie中的字符串值 
     */  
    public static String getCookie(HttpServletRequest request, String cookieName) {
  
        Cookie cookies[] = request.getCookies();
        if (cookies != null) {  
            for (Cookie cookie : cookies) {
                if (cookie != null && cookie.getName().equals(cookieName)) {  
                    return cookie.getValue();
                }
            }
        }
        return null;  
    }  
  
    /** 
     * 设置指定cookie中的值(1.得到原先cookie中的值;2.重新设置cookie的值;3.保存重置后的cookie) 
     *  
     * @param request 
     * @param response 
     * @param cookieName 
     *            要设置的cookie的名字 
     * @param goodsid 
     *            要添加到浏览历史中的 goodsID号 
     * @param count 
     *            总共可以显示的历史记录条数 
     */  
    public static void setCookie(HttpServletRequest request,
                                 HttpServletResponse response, String cookieName, String goodsid,
                                 int count) {
        // 得到指定的cookie  
        String ids = getCookie(request, cookieName);  
        //有值就不要再设置了
        
    	// 设置cookie中格的浏览记录  
        ids = setValue(ids, goodsid, count);  
        // 保存cookie  
        saveCookie(request, response, cookieName, ids);  
        
    }  
  
    // 测试方法  
    public static void main(String[] args) {  
        System.out.println(setValue(null, "1", 3));  
        System.out.println(setValue("1,2,3", "1", 3));  
        System.out.println(setValue("2,1,3", "1", 3));  
        System.out.println(setValue("2,1", "1", 3));  
        System.out.println(setValue("2,3,4", "1", 3));  
        System.out.println(setValue("2,4", "1", 3));  
        System.out.println(setValue("4,3,1", "1", 3));  
    }  
  
    /** 
     * 设置浏览历史字符串 
     *  
     * @param ids 
     * @param sbookid 
     *            最新浏览的id号 
     * @return 修改后的字符串 
     */  
    private static String setValue(String ids, String bookid, int count) {  
        // 1、 没有任何记录--》直接添加 id  
        // 2、 1,2,3 4--》 4,1,2  
        // 3、 1,2,3 2 --》 2,1,3  
        // 4、1,2 3--》 3,1,2  
        // 如果不存在Cookie或者Cookie中没有值  
        StringBuffer sb = new StringBuffer();  
        if (ids == null) {  
            sb.append(bookid);  
        } else {  
            List<String> list = Arrays.asList(ids.split("\\,"));  
            LinkedList<String> idsList = new LinkedList<String>(list);  
            // 未浏览过  
            if (!idsList.contains(bookid)) {  
                if (idsList.size() < count) {  
                    idsList.addFirst(bookid);  
                } else {  
                    idsList.removeLast();  
                    idsList.addFirst(bookid);  
                }  
            } else {  
                // 如果包含已浏览的  
                idsList.remove(bookid);  
                idsList.addFirst(bookid);  
            }  
            for (String id : idsList) {  
                sb.append(id).append(",");  
            }  
            if (sb != null && sb.length() > 0) {  
                sb.deleteCharAt(sb.length() - 1);  
            }  
        }  
        return sb.toString();  
    }  
  
    /** 
     * 保存cookie的值 
     *  
     * @param request 
     * @param response 
     * @param cookieName 
     *            要保存的cookie的名字 
     * @param value 
     *            保存到cookie中的值 
     */  
    public static void saveCookie(HttpServletRequest request,
                                  HttpServletResponse response, String cookieName, String value) {
        saveCookie(request, response, cookieName, value, COOKIE_LIFE_TIME);  
    }  
  
    /** 
     * 删除指定的cookie 
     *  
     * @param request 
     * @param response 
     * @param cookieName 
     *            要删除的cookie 
     */  
    public static void deleteCookie(HttpServletRequest request,
                                    HttpServletResponse response, String cookieName) {
        saveCookie(request, response, cookieName, "", 0);  
    }  
  
    /** 
     * 保存cookie 并设置cookie存活的时间 
     *  
     * @param request 
     * @param response 
     * @param cookieName 
     *            要保存的cookie的名字 
     * @param value 
     *            cookie中要存放的值 
     * @param time 
     *            cookie存活时间 
     */  
    public static void saveCookie(HttpServletRequest request,
                                  HttpServletResponse response, String cookieName, String value,
                                  int time) {
        Cookie cookie = new Cookie(cookieName, value);
        cookie.setMaxAge(time);// 设置Cookie的存活时间  
        //cookie.setPath(request.getServletContext().getContextPath());
        cookie.setPath(JWTUtils.Cookie_path);
        response.addCookie(cookie);// 保存cookie  
    }

    /**
     * 保存cookie,并可以设置cookie的保存路径
     *
     * @param path cookie保存路径
     *
     * @author LiaoTeng
     * @date 2022-11-12
     */
    public static void saveCookie(HttpServletResponse response, String cookieName, String value, String path) {
        Cookie cookie = new Cookie(cookieName, value);
        cookie.setPath(path);
        cookie.setMaxAge(COOKIE_LIFE_TIME);// 设置Cookie的存活时间
        response.addCookie(cookie);
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值