1、在pom.xml添加依賴
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.4.0</version> </dependency>
2、自定義兩個注解PassToken、UserLoginToken
package com.cn.commodity.annotations; 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; }
package com.cn.commodity.annotations; 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; }
3、定義一個獲取token的服務TokenService
package com.cn.commodity.service; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.cn.commodity.entity.User; import org.springframework.stereotype.Service; @Service("tokenService") public class TokenService { public String getToken(User user) { //生成token String token=""; token= JWT.create().withAudience(String.valueOf(user.getId())) .sign(Algorithm.HMAC256(user.getPassword())); return token; } }
4、定義一個攔截器

package com.cn.commodity.interceptor; 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.cn.commodity.annotations.PassToken; import com.cn.commodity.annotations.UserLoginToken; import com.cn.commodity.entity.User; import com.cn.commodity.service.UserService; 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; public class AuthenticationInterceptor implements HandlerInterceptor { @Autowired UserService userService; @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception { String token = httpServletRequest.getHeader("token");// 從 http 請求頭中取出 token // 如果不是映射到方法直接通過 if (!(object instanceof HandlerMethod)) { return true; } HandlerMethod handlerMethod = (HandlerMethod) object; 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 中的 user id String userId; try { userId = JWT.decode(token).getAudience().get(0); } catch (JWTDecodeException j) { throw new RuntimeException("401"); } User user = userService.getUserById(Integer.parseInt(userId)); if (user == null) { throw new RuntimeException("用戶不存在,請重新登錄"); } // 驗證 token JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build(); try { jwtVerifier.verify(token); } catch (JWTVerificationException e) { throw new RuntimeException("401"); } return true; } } return true; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }
5、在項目中應用該攔截器
package com.cn.commodity.interceptor; 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(authenticationInterceptor()) .addPathPatterns("/**"); // 攔截所有請求,通過判斷是否有 @LoginRequired 注解 決定是否需要登錄 } @Bean public AuthenticationInterceptor authenticationInterceptor() { return new AuthenticationInterceptor(); } }
6、在controller層應用注解進行驗證
package com.cn.commodity.controller;
import com.alibaba.fastjson.JSONObject;
import com.cn.commodity.annotations.PassToken;
import com.cn.commodity.annotations.UserLoginToken;
import com.cn.commodity.dao.UserDao;
import com.cn.commodity.entity.User;
import com.cn.commodity.service.TokenService;
import com.cn.commodity.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
@RequestMapping("api")
public class UserApi {
@Autowired
UserService userService;
@Autowired
TokenService tokenService;
@Resource
private UserDao userDao;
//登錄
@PostMapping("/login")
public Object login(@RequestBody User user){
JSONObject jsonObject=new JSONObject();
//User userForBase=userService.getUserById(user.getId());
User userForBase=userDao.selectOne(user);
if(userForBase==null){
jsonObject.put("message","登錄失敗,用戶不存在");
return jsonObject;
}else {
if (!userForBase.getPassword().equals(user.getPassword())){
jsonObject.put("message","登錄失敗,密碼錯誤");
return jsonObject;
}else {
String token = tokenService.getToken(userForBase);
jsonObject.put("token", token);
jsonObject.put("user", userForBase);
return jsonObject;
}
}
}
@UserLoginToken
@GetMapping("/getMessage")
public String getMessage(){
return "你已通過驗證";
}
@PassToken
@GetMapping("/skipToken")
public String skipToken(){
return "跳過passToken認證";
}
}
7、運行測試
a) 登陸獲取token
#獲取token,在項目中可以將token和user組合存在redis中。
post請求參數: { "userName":"yangwj1", "password":"wj1" } 請求url:http://localhost:8080/api/login 返回參數: { "user": { "id": 2, "userName": "yangwj1", "password": "wj1", "age": 1 }, "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIyIn0.z2EzbIbYLCmw5PM5Yx9arE5QGUH9ET_AC0BEy9SyE8A" }
b)跳過token認證
請求url:http://localhost:8080/api/skipToken 返回參數:跳過passToken認證
c)對api進行token驗證
請求參數header中: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIyIn0.z2EzbIbYLCmw5PM5Yx9arE5QGUH9ET_AC0BEy9SyE8A 請求url:http://localhost:8080/api/getMessage 返回參數:你已通過驗證