赞
踩
为什么使用token???
在开发过程中,使用token可以提供一种安全的身份验证机制,确保只有经过授权的用户才能访问特定的资源或执行特定的操作。Token可以在用户登录后生成并存储在客户端,然后在每次请求时通过HTTP头部或其他方式发送给服务器进行验证。这种方式相对于传统的基于session的认证方式更加灵活和安全,可以有效防止常见的安全攻击,如跨站点请求伪造(CSRF)和会话劫持等。
<!-- JWT -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.3</version>
</dependency>
package com.qingge.springboot.utils; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.qingge.springboot.entity.User; import com.qingge.springboot.service.IUserService; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.annotation.PostConstruct; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.Date; @Component public class TokenUtils { private static IUserService staticUserService; @Resource private IUserService userService; // 依赖注入之后、初始化方法调用之前被调用 @PostConstruct public void setUserService() { staticUserService = userService; } /** * 生成token * * @return */ public static String genToken(String userId, String sign) { return JWT.create().withAudience(userId) // 将 user id 保存到 token 里面,作为载荷 .withExpiresAt(DateUtil.offsetHour(new Date(), 2)) // 2小时后token过期 .sign(Algorithm.HMAC256(sign)); // 以 password 作为 token 的密钥 } /** * 获取当前登录的用户信息 * * @return user对象 */ public static User getCurrentUser() { try { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String token = request.getHeader("token"); if (StrUtil.isNotBlank(token)) { String userId = JWT.decode(token).getAudience().get(0); return staticUserService.getById(Integer.valueOf(userId)); } } catch (Exception e) { return null; } return null; } }
Token示例:
项目结构如下:
package com.ppj.config.interceptor; import cn.hutool.core.util.StrUtil; 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.exceptions.JWTVerificationException; import com.ppj.constants.Constants; import com.ppj.entity.User; import com.ppj.exception.ServiceException; import com.ppj.service.IUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class JwtInterceptor implements HandlerInterceptor { @Autowired private IUserService userService; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String token = request.getHeader("token"); // 如果不是映射到方法直接通过 if(!(handler instanceof HandlerMethod)){ return true; } // 执行认证 if (StrUtil.isBlank(token)) { throw new ServiceException(Constants.CODE_401, "无token,请重新登录"); } // 获取 token 中的 user id String userId; try { userId = JWT.decode(token).getAudience().get(0); } catch (JWTDecodeException j) { throw new ServiceException(Constants.CODE_401, "token验证失败,请重新登录"); } // 根据token中的userid查询数据库 User user = userService.getById(userId); if (user == null) { throw new ServiceException(Constants.CODE_401, "用户不存在,请重新登录"); } // 用户密码加签验证 token JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build(); try { jwtVerifier.verify(token); // 验证token } catch (JWTVerificationException e) { throw new ServiceException(Constants.CODE_401, "token验证失败,请重新登录"); } return true; } }
InterceptorConfig.java
package com.qingge.springboot.config; import com.qingge.springboot.config.interceptor.JwtInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class InterceptorConfig implements WebMvcConfigurer { // 添加拦截器 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(jwtInterceptor()) .addPathPatterns("/**") // 拦截所有请求,通过判断token是否合法来决定是否需要登录 .excludePathPatterns("/user/login", "/user/register", "/**/export", "/**/import"); } @Bean public JwtInterceptor jwtInterceptor() { return new JwtInterceptor(); } }
修改UserServiceImpl中登录方法,登录成功后,设置Token;在UserDTO中添加token属性
package com.ppj.entity.dto;
import lombok.Data;
/**
* 接受前端登录请求的参数
*/
@Data
public class UserDTO {
private String username;
private String password;
private String nickname;
private String avatarUrl;
private String token;
}
@Override
public UserDTO login(UserDTO userDTO) {
User one = getUserInfo(userDTO);
if (one != null) {
BeanUtil.copyProperties(one, userDTO, true);
// 设置token
String token = TokenUtils.genToken(one.getId().toString(), one.getPassword());
userDTO.setToken(token);
return userDTO;
} else {
throw new ServiceException(Constants.CODE_600, "用户名或密码错误");
}
}
// request 拦截器
// 可以自请求发送前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config => {
config.headers['Content-Type'] = 'application/json;charset=utf-8';
let user = localStorage.getItem("loginUser") ? JSON.parse(localStorage.getItem("loginUser")) : null
if (user) {
config.headers['token'] = user.token; // 设置请求头
}
return config
}, error => {
return Promise.reject(error)
});
// response 拦截器 // 可以在接口响应后统一处理结果 request.interceptors.response.use( response => { let res = response.data; // 如果是返回的文件 if (response.config.responseType === 'blob') { return res } // 兼容服务端返回的字符串数据 if (typeof res === 'string') { res = res ? JSON.parse(res) : res } // 当权限验证不通过的时候,直接跳转到登录页 if (res.code === '401') { router.push("/login") } return res; }, error => { console.log('err' + error) // for debug return Promise.reject(error) } )
项目源于此地址:程序员青戈
如果此文对您有所帮助,请帅戈靓女们务必不要吝啬你们的Zan,感谢!!不懂的可以在评论区评论,有空会及时回复。
文章会一直更新
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。