一 准备
1 引入依赖
common-util中引入jwt依赖
<!-- JWT相关依赖-->
<dependencies>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
</dependencies>
2 引入工具类
common-util中引入工具类:JwtUtils.java、JwtInfo.java
JwtUtils.java
public class JwtUtils {
/**
* 密钥字符串
*/
public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";
/**
* 功能描述:获得密钥实例
*
* @return Key 密钥实例
* @author cakin
* @date 2020/12/27
*/
private static Key getKeyInstance() {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
byte[] bytes = DatatypeConverter.parseBase64Binary(APP_SECRET);
return new SecretKeySpec(bytes, signatureAlgorithm.getJcaName());
}
/**
* 功能描述:获取Jwt的token
*
* @param jwtInfo 用户信息
* @param expire 过期时间
* @return String
* @author cakin
* @date 2020/12/27
*/
public static String getJwtToken(JwtInfo jwtInfo, int expire) {
String JwtToken = Jwts.builder()
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
.setSubject("guli-user") // 主题
.setIssuedAt(new Date()) // 颁发时间
.setExpiration(DateTime.now().plusSeconds(expire).toDate()) // 过期时间
.claim("id", jwtInfo.getId()) // 用户id
.claim("nickname", jwtInfo.getNickname()) // 用户昵称
.claim("avatar", jwtInfo.getAvatar()) // 用户头像
.signWith(SignatureAlgorithm.HS256, getKeyInstance())
.compact();
return JwtToken;
}
/**
* 判断token是否存在与有效
*
* @param jwtToken jwtToken
* @return boolean 是否有效
*/
public static boolean checkJwtTToken(String jwtToken) {
if (StringUtils.isEmpty(jwtToken)) return false;
try {
Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 判断token是否存在与有效
*
* @param request http请求
* @return boolean JWT是否有效
*/
public static boolean checkJwtTToken(HttpServletRequest request) {
try {
String jwtToken = request.getHeader("token");
if (StringUtils.isEmpty(jwtToken)) return false;
Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 根据token获取会员id
*
* @param request http请求
* @return JwtInfo JWt中的会员信息
*/
public static JwtInfo getMemberIdByJwtToken(HttpServletRequest request) {
String jwtToken = request.getHeader("token");
if (StringUtils.isEmpty(jwtToken)) return null;
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(jwtToken);
Claims claims = claimsJws.getBody();
JwtInfo jwtInfo = new JwtInfo(claims.get("id").toString(), claims.get("nickname").toString(), claims.get("avatar").toString());
return jwtInfo;
}
}
JwtInfo.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class JwtInfo {
/**
* 用户id
*/
private String id;
/**
* 昵称
*/
private String nickname;
/**
* 图像
*/
private String avatar;
//权限、角色等
//不要存敏感信息
}
二 用户登录接口
1 定义LoginVo
/**
* @className: LoginVo
* @description: 用户登录信息
* @date: 2020/12/27
* @author: cakin
*/
@Data
public class LoginVo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 手机号
*/
private String mobile;
/**
* 用户密码
*/
private String password;
}
2 service实现登录
接口:MemberService
/**
* 功能描述:登录接口
*
* @author cakin
* @date 2020/12/27
* @param loginVo 用户登录信息
* @return String Jwt token
*/
String login(LoginVo loginVo);
实现: MemberServiceImpl
/**
* 功能描述:登录接口
*
* @param loginVo 用户登录信息
* @return String Jwt token
* @author cakin
* @date 2020/12/27
*/
@Override
public String login(LoginVo loginVo) {
String mobile = loginVo.getMobile();
String password = loginVo.getPassword();
// 校验:参数(手机号、密码)是否合法
if (StringUtils.isEmpty(mobile)
|| !FormUtils.isMobile(mobile)
|| StringUtils.isEmpty(password)) {
throw new GuliException(ResultCodeEnum.PARAM_ERROR);
}
// 校验手机号是否存在
QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("mobile", mobile);
Member member = baseMapper.selectOne(queryWrapper);
if (member == null) {
throw new GuliException(ResultCodeEnum.LOGIN_MOBILE_ERROR);
}
// 校验密码是否正确
if (!MD5.encrypt(password).equals(member.getPassword())) {
throw new GuliException(ResultCodeEnum.LOGIN_PASSWORD_ERROR);
}
// 校验用户是否被禁用
if (member.getDisabled()) {
throw new GuliException(ResultCodeEnum.LOGIN_DISABLED_ERROR);
}
// 登录:生成token
JwtInfo info = new JwtInfo();
info.setId(member.getId());
info.setNickname(member.getNickname());
info.setAvatar(member.getAvatar());
String jwtToken = JwtUtils.getJwtToken(info, 1800);
return jwtToken;
}
3 登录接口
/**
* 功能描述:登录接口
*
* @author cakin
* @date 2020/12/27
* @param loginVo 登录信息
* @return R 返回给前端的信息
*/
@ApiOperation(value = "会员登录")
@PostMapping("login")
public R login(@RequestBody LoginVo loginVo){
String token = memberService.login(loginVo);
return R.ok().data("token", token).message("登录成功");
}
三 前端整合
1 安装cookie模块
npm install js-cookie@2.2.0
2 api
import request from '~/utils/request'
// import cookie from 'js-cookie'
// 提交登录信息
export default {
submitLogin(user) {
return request({
baseURL: 'http://localhost:8160',
url: '/api/ucenter/member/login',
method: 'post',
data: user
})
},
}
3 登录页核心代码
import cookie from 'js-cookie'
import loginApi from '~/api/login'
export default {
layout: 'sign',
data() {
return {
user: {
mobile: '',
password: ''
}
}
},
methods: {
// 登录
submitLogin() {
// 执行远程登录接口调用
loginApi.submitLogin(this.user).then(response => {
// 将jwt写入cookie
cookie.set('guli_jwt_token', response.data.token, { domain: 'localhost' })
// 跳转到网站的首页面
window.location.href = '/'
})
}
}
}
</script>
4 测试
查看cookie中存储了jwtToken值