前后台分离使用token
使用场景:前后端分离时(后台使用的是springboot,前端使用的是uniapp),当前台请求登录接口时,后台进行储存用户信息,并生成token,并返回给前端.前端请求其他接口都需要在头部带着token ,才能请求。下面来具体代码说明吧。(对你们有帮助的谢谢点赞收藏,错误的地方也谢谢评论提出,加以改善)
第一步:在pom.xml 文件中引入jar包
<!-- token包--> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency>
第二步:使用工具类JwtUtils.java (这是生成token,和获取token的机制,直接复制可用)
package com.example.changcai.smart_device.tool; import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.apache.tomcat.util.codec.binary.Base64; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import javax.servlet.http.HttpServletRequest; import java.security.Key; import java.util.Date; import java.util.Map; /** * jwt */ public class JwtUtils { /** * @param claims 自定义的 map * @param ttl 过期时间 * @return */ public static String createToken(Map<String, Object> claims, Long ttl) { Key key = generateKey(); SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; Long nowMillis = System.currentTimeMillis(); JwtBuilder builder = Jwts.builder() .setHeaderParam("typ", "JWT") .setHeaderParam("alg", "HS256") .setClaims(claims) .signWith(signatureAlgorithm, key); if (ttl != null && ttl >= 0) { Long expMillis = nowMillis + ttl * 1000; Date exp = new Date(expMillis); builder.setExpiration(exp); } return builder.compact(); } /** * @param claims 自定义的 map * @return */ public static String createToken(Map<String, Object> claims) { return createToken(claims, null); } /** * @param jwt 创建的 jwt 字符串 * @return */ public static Claims parse(String jwt) { if (jwt == null) { return null; } try { return Jwts.parser() .setSigningKey(generateKey()) .parseClaimsJws(jwt) .getBody(); } catch (Exception e) { return null; } } /** * @return */ private static SecretKey generateKey() { String stringKey = "changcai"; byte[] encodedKey = Base64.decodeBase64(stringKey); return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES"); } /** * @return */ public static Integer getParseToken(HttpServletRequest request, String token, String key) { Claims parse = parse(token); if (parse == null) { return null; } return (Integer) parse.get(key); } public static Integer getParseToken(String token, String key) { Claims parse = parse(token); if (parse == null) { return null; } return (Integer) parse.get(key); } /*public static String getParseTokenStr(HttpServletRequest request, String token, String key) { Claims parse = parse(token); if (parse == null) { return null; } return (String) parse.get(key); }*/ public static Long parseTokenStr(String token, String key) { Claims parse = parse(token); Object uid = parse.get(key); return Long.parseLong(uid.toString()); } public static void main(String[] args) { System.out.println(generateKey()); } }
第三步:后台登录接口存储token,并返回给前端 该controller 继承一个BaseController
@ApiOperation("用户登录接口Token") @RequestMapping(value = "wechatLoginToken",method = RequestMethod.POST) @ResponseBody public ResultInfo wechatLoginToken(@RequestBody @ApiParam("用户对象") Member member1){ HashMap<String,Object> map=new HashMap(); Member member=memberService.byUserName(member1.getUsername()); if(null==member){ return new ResultInfo(203,"用户不存在!",false); }else{ if("1".equals(member.getIsEnable())){ return new ResultInfo(204,"用户已禁用!",false); }else if("1".equals(member.getIsDeleted())){ return new ResultInfo(204,"用户已删!",false); }else{ if(!member.getPassword().equals(MD5Util.md5(member1.getPassword()))){ return new ResultInfo(203,"用户密码不正确!",false); }else{ //登录成功后 HashMap<String, Object> claims = new HashMap<>(); claims.put("id", member.getId()); //token过期时间24小时 String token = JwtUtils.createToken(claims, 864000L); map.put("token",token); map.put("member",member); return new ResultInfo(200,"用户登录成功!",map); } } } }
第四步:BaseController(主要解析token )
package com.example.changcai.smart_device.controller; import com.example.changcai.smart_device.entity.Member; import com.example.changcai.smart_device.service.MemberService; import com.example.changcai.smart_device.tool.JwtUtils; import com.github.pagehelper.util.StringUtil; import io.jsonwebtoken.Claims; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.ModelAttribute; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Slf4j @Component public class BaseController { @Resource protected HttpServletRequest request; @Resource protected HttpServletResponse response; @Resource private MemberService memberService; protected Member member; @ModelAttribute public Member getMember() { String token = request.getHeader("X-Token"); if (StringUtil.isNotEmpty(token)) { System.out.println("token的值:"+token); Claims parse = JwtUtils.parse(token); Object obj = parse.get("id"); member = memberService.getById(obj.toString()); return member; } return null; } }
测试登录后返回的值
再写一个controller测试类,登录后,传token 获取member 对象
@ApiOperation("通过Token获取用户") @RequestMapping(value = "byTokenGetMember",method = RequestMethod.POST) @ResponseBody public ResultInfo byTokenGetMember(){ return new ResultInfo(200,"用户登录成功!",member); }
测试效果如
注意点1:前端请求其他接口时,都需要把token 带在头部,参数格式是:
headers:{
X-Token:前端登录成功后保存的token值
}
注意点2:如果项目使用到了swagger,请求接口heard头部想显示“X-Token”
代码截图
效果: