SpringBoot+JWT實現token驗證並將用戶信息存儲到@註解內

springboot集成jwt實現token驗證
一、引入jwt依賴
<!--jwt-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>

        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.9.0</version>
        </dependency>
二、自定義兩個註解
/**
 * 忽略Token驗證
 *
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IgnoreAuth {
    boolean required() default true;
}
/**
 * 登陸用戶信息
 *
 */
@Target({ElementType.PARAMETER,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginUser {
    boolean required() default true;
}

@Target:註解的做用目標
@Target(ElementType.TYPE)——接口、類、枚舉、註解
@Target(ElementType.PARAMETER)——方法參數
@Target(ElementType.METHOD)——方法
三、定義一個用戶實體類
/**
 * 用戶類
 *
 */

@Data
@ApiModel(value="User對象", description="用戶表")
public class User extends BaseEntity<User> {

private static final long serialVersionUID=1L;

    @ApiModelProperty(value = "編號")
    private String id;

    @ApiModelProperty(value = "歸屬公司")
    private String companyId;

    @ApiModelProperty(value = "歸屬部門")
    private String officeId;

    @ApiModelProperty(value = "登陸名")
    private String loginName;

    @ApiModelProperty(value = "密碼")
    private String password;

    @ApiModelProperty(value = "工號")
    private String no;

    @ApiModelProperty(value = "姓名")
    private String name;

    @ApiModelProperty(value = "郵箱")
    private String email;

    @ApiModelProperty(value = "電話")
    private String phone;

    @ApiModelProperty(value = "手機")
    private String mobile;

    @ApiModelProperty(value = "用戶類型")
    private String userType;

    @ApiModelProperty(value = "用戶頭像")
    private String photo;

    @ApiModelProperty(value = "最後登錄IP")
    private String loginIp;

    @ApiModelProperty(value = "最後登錄時間",example = "2019-11-22 00:00:00")
    private Date loginDate;

    @EnumFormat
    @ApiModelProperty(value = "登陸狀態 : 0 正常,1 異常")
    private UserLoginFlagEnum loginFlag;

    @ApiModelProperty(value = "建立者")
    private String createBy;

    @ApiModelProperty(value = "建立時間",example = "2019-11-22 00:00:00")
    private Date createDate;

    @ApiModelProperty(value = "更新者")
    private String updateBy;

    @ApiModelProperty(value = "更新時間",example = "2019-11-22 00:00:00")
    private Date updateDate;

    @ApiModelProperty(value = "備註信息")
    private String remarks;

    @TableLogic
    @ApiModelProperty(value = "刪除標記")
    private String delFlag;

    @ApiModelProperty(value = "微信openid")
    private String openid;


    @Override
    protected Serializable pkVal() {
        return this.id;
    }

}
四、生成token
@Service("TokenService")
public class TokenService {
    public String getToken(User user) {
        String token="";
        token= JWT.create().withAudience(user.getId())// 將 user id 保存到 token 裏面
                .sign(Algorithm.HMAC256(user.getOpenid()));// 以 OpenId 做爲 token 的密鑰
        return token;
    }
}
五、設置攔截器
@Component
public class AuthorizationInterceptor implements HandlerInterceptor {
    @Autowired
    IUserService userService;

    public static final String LOGIN_USER_KEY = "LOGIN_USER_KEY";


    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
        //支持跨域請求
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
        httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
        httpServletResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with,X-Nideshop-Token,X-URL-PATH");
        httpServletResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("Origin"));

        String token = httpServletRequest.getHeader("token");// 從 http 請求頭中取出 token
        

        // 若是不是映射到方法直接經過
        if(!(object instanceof HandlerMethod)){
            return true;
        }
        HandlerMethod handlerMethod=(HandlerMethod)object;
        Method method=handlerMethod.getMethod();
        //檢查是否有IgnoreAuth註釋,有則跳過認證
        if (method.isAnnotationPresent(IgnoreAuth.class)) {
            IgnoreAuth passToken = method.getAnnotation(IgnoreAuth.class);
            if (passToken.required()) {
                return true;
            }
        }
        //檢查有沒有須要用戶權限的註解
        if (method.isAnnotationPresent(LoginUser.class)) {
            LoginUser userLoginToken = method.getAnnotation(LoginUser.class);
            if (userLoginToken !=null) {
                // 執行認證
                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");
                }
                //設置userId到request裏,後續根據userId,獲取用戶信息
                httpServletRequest.setAttribute(LOGIN_USER_KEY, userId);

                User user = userService.getById(userId);
                if (user == null) {
                    throw new RuntimeException("用戶不存在,請從新登陸");
                }
                // 驗證 token
                JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getOpenid())).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 {
    }
}
六、配置攔截器

在配置類上添加了註解@Configuration,標明瞭該類是一個配置類而且會將該類做爲一個SpringBean添加到IOC容器內java

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authenticationInterceptor())
                .addPathPatterns("/**");   
    }
    @Bean
    public AuthenticationInterceptor authenticationInterceptor() {
        return new AuthenticationInterceptor();
    }
}
七、token驗證流程

一、用戶登陸是生成token
二、從http請求頭中取出token
三、判斷是否映射到方法
四、檢查是否有@IgnoreAuth註釋,有則跳過認證
五、檢查是否有用戶登陸的註解,有則須要取出並驗證
六、認證經過則能夠訪問web

相關文章
相關標籤/搜索