记一次实战项目所学(JWT篇)
5. 登录验证功能
先获取公钥准备将前端输入的进行加密
//获得公钥@GetMapping("/rsa-pks")public JsonResponse<String> getRsaPublicKey(){String publicKeyStr = RSAUtil.getPublicKeyStr();return new JsonResponse<>(publicKeyStr);}
新建(注册)一个user
(controller层)
//新建一个用户@PostMapping("/users") //@RequestBody 把User 封装成json数据返回public JsonResponse<String>addUser(@RequestBody User user){userService.addUser(user);return JsonResponse.success();}
(Service层)
@Service
public class UserService {@Autowiredprivate UserDao userDao;public void addUser(User user) {String phone = user.getPhone();if (StringUtils.isNullOrEmpty(phone)) {throw new ConditionException("手机号不能为空!");}User dbUser = this.getUserByPhone(phone);if (dbUser != null) {throw new ConditionException("该手机号已经被注册");}//加密需要Date now = new Date();//md5需要加密String salt = String.valueOf(now.getTime());String password = user.getPassword();String rawPassword;try {rawPassword = RSAUtil.decrypt(password);//该密码已经通过前端获取的公钥加密} catch (Exception e) {throw new ConditionException("解密失败");}String md5Password = MD5Util.sign(rawPassword, salt, "UTF-8");user.setSalt(salt);user.setPassword(md5Password);user.setCreateTime(now);userDao.addUser(user);//添加用户信息(这里有两张表user和userinfo )UserInfo userInfo = new UserInfo();userInfo.setUserId(user.getId());userInfo.setNick(UserConstant.DEFAULT_NICK);userInfo.setBirth(UserConstant.DEFAULT_BIRTH);userInfo.setGender(UserConstant.GENDER_FEMALE);userInfo.setCreateTime(now);userDao.addUserInfo(userInfo);}public User getUserByPhone(String phone) {return userDao.getUserByPhone(phone);}
dao层为数据操作不再贴代码啦
用户登录
controller
//用户登录@PostMapping("/user-tokens")public JsonResponse<String> login(@RequestBody User user) throws Exception{String token=userService.login(user);return new JsonResponse<>(token);}
service
public String login(User user) throws Exception {String phone = user.getPhone();if (StringUtils.isNullOrEmpty(phone)) {throw new ConditionException("手机号不能为空!");}User dbUser = this.getUserByPhone(phone);if (dbUser == null) {throw new ConditionException("当前用户不存在");}String password = user.getPassword();String rowpassword;try {rowpassword = RSAUtil.decrypt(password);} catch (Exception e) {throw new ConditionException("密码解密失败");}String salt = dbUser.getSalt();String md5Password = MD5Util.sign(rowpassword, salt, "UTF-8");if (!md5Password.equals(dbUser.getPassword())) {throw new ConditionException("密码错误!");}return TokenUtil.generateToken(dbUser.getId());}
前端加密不安全,数据库存入的密码应该是不可逆的,每次认证时候前端传入密码加密后跟后端数据库里密码比对,如果一样密码正确,如果不一样密码不正确,前端加密后传输是怕传输过程被拦截获取到明文密码
因为id是唯一的所以id可以作为token
5.5 基于JWT的用户的token验证
依赖
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.18.2</version></dependency>
util.token
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.imooc.bilibili.domain.except.ConditionException;import java.util.Calendar;
import java.util.Date;public class TokenUtil {private static final String ISSUER="签发者"; //签发者是谁,随意填public static String generateToken(Long userId) throws Exception{Algorithm algorithm = Algorithm.RSA256(RSAUtil.getPublicKey(),RSAUtil.getPrivateKey());Calendar calendar =Calendar.getInstance(); //用于实现过期时间calendar.setTime(new Date());calendar.add(Calendar.SECOND,30); //30s过期return JWT.create().withKeyId(String.valueOf(userId)).withIssuer(ISSUER).withExpiresAt(calendar.getTime()).sign(algorithm);}//解密public static Long verifyToken(String token) {try{Algorithm algorithm =Algorithm.RSA256(RSAUtil.getPublicKey(),RSAUtil.getPrivateKey());JWTVerifier verifier =JWT.require(algorithm).build();DecodedJWT jwt= verifier.verify(token);String keyId = jwt.getKeyId();return Long.valueOf(keyId);}catch (TokenExpiredException e){throw new ConditionException("555","token过期!");}catch (Exception e){throw new ConditionException("非法用户token");}}
}
需要一个通用方法,获取token里的userid(一般放在请求头里)
import com.imooc.bilibili.domain.except.ConditionException;
import com.imooc.bilibili.service.Util.TokenUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.ServletRequest;@Component
public class UserSupport {public Long getCurrentUserId(){//抓取请求上下文,获取token(在请求头中)+ServletRequestAttributes requestAttributes =(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();String token =requestAttributes.getRequest().getHeader("token");Long userId= TokenUtil.verifyToken(token);if(userId<0){throw new ConditionException("非法用户!");}return userId;}
}