一、添加依赖
<!--JWT--> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.4.0</version> </dependency>
二、自定义俩个注解,一个用于跳过JWT验证,一个用于JWT验证
1、用来跳过验证的自定义注解PassToken
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 用来跳过验证的注解 */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface PassToken { boolean required() default true; }
2、用来验证的注解UserLoginToken
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 需要登录才能进行操作的注解 */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface UserLoginToken { boolean required() default true; }
三、自定义实体类User
import javax.persistence.*; import java.util.Date; @Entity @Table(name = "read_user") public class User { //主键id @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Integer id; //用户名 @Column(name = "read_username") private String read_username; //邮箱 @Column(name = "read_useremail") private String read_useremail; //密码 @Column(name = "read_userpass") private String read_userpass; //创建时间 @Column(name = "read_usercreatetime") private Date read_usercreatetime; setter/getter方法 }
四、书写JWT工具类
import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.dream.fly.readbook.entity.User; /** * 生成token的方法 */ public class JWTUtil { /** *Algorithm.HMAC256():使用HS256生成token,密钥则是用户的密码,唯一密钥的话可以保存在服务端 * withAudience()存入需要保存在token的信息,这里存入的是用户账号 * @param user * @return */ public static String getToken(User user){ String token = ""; token = JWT.create().withAudience(user.getRead_username()) .sign(Algorithm.HMAC256(user.getRead_userpass())); return token; } }
五、书写拦截器,对程序方法进行拦截验证
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.dream.fly.readbook.CustomAnno.PassToken; import com.dream.fly.readbook.CustomAnno.UserLoginToken; import com.dream.fly.readbook.entity.User; import com.dream.fly.readbook.service.ProjectService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.lang.reflect.Method; /** * 拦截器 * 获取token并验证token */ public class JWTAuthenticationInterceptor implements HandlerInterceptor { @Autowired private ProjectService projectService; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("token"); //从http请求头中取出token //如果不是映射到方法就直接通过 if(!(handler instanceof HandlerMethod)){ return true; } HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); //检查是否有passtoken注释,有则跳过认证 if(method.isAnnotationPresent(PassToken.class)){ PassToken passToken = method.getAnnotation(PassToken.class); if(passToken.required()){ return true; } } //检查有没有需要用户权限的注释 if(method.isAnnotationPresent(UserLoginToken.class)){ UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class); if(userLoginToken.required()){ //执行认证 if(token == null){ throw new RuntimeException("无token,请重新登录!"); } //获取token中的username String username; try { username = JWT.decode(token).getAudience().get(0); }catch (JWTDecodeException j){ throw new RuntimeException("401"); } User user = this.projectService.findUserByName(username); if(user == null){ throw new RuntimeException("用户不存在,请重新登录!"); } //验证token JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getRead_userpass())).build(); try { jwtVerifier.verify(token); }catch (JWTVerificationException e){ throw new RuntimeException("401"); } return true; } } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
六、书写配置类,将拦截器配置到项目中
import com.dream.fly.readbook.utils.JWTAuthenticationInterceptor; 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 JWTInterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(jwtAuthenticationInterceptor()) .addPathPatterns("/**"); // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录 } @Bean public JWTAuthenticationInterceptor jwtAuthenticationInterceptor(){ return new JWTAuthenticationInterceptor(); } }
七、分别书写登录和获取所有信息接口,进行验证。如果getMessage接口不在header中携带token值,是无法访问的。
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.dream.fly.readbook.CustomAnno.UserLoginToken; import com.dream.fly.readbook.entity.User; import com.dream.fly.readbook.service.ProjectService; import com.dream.fly.readbook.utils.JWTUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.ModelAndView; import java.util.HashMap; import java.util.Map; @RestController @Api(tags = "项目初始化接口") public class ProjectCotroller { @Autowired private ProjectService projectService; /** * 用户登录 * @param username 用户名 * @param passwd 密码 * @return */ @PostMapping("/userLogin") @ApiOperation(value = "用户登录",notes = "用户登录") @ApiImplicitParams({@ApiImplicitParam(name = "username",value = "登录账号",required = true,paramType = "query") ,@ApiImplicitParam(name = "passwd",value = "登录密码",required = true,paramType = "query")}) public JSONObject userLogin(String username,String passwd){ Boolean loginInfo = this.projectService.userLogin(username, passwd); Map map = new HashMap(); map.put("loginInfo",loginInfo); if (loginInfo){ //如果登录成功需要把token带给前端 User user = new User(); user.setRead_username(username); user.setRead_userpass(passwd); String token = JWTUtil.getToken(user); map.put("token",token); } JSONObject jsonObject = new JSONObject(map); return jsonObject; } @UserLoginToken @GetMapping("/getMessage") public String getMessage(){ return "你已经通过验证"; } }