springboot +jjwt+注解实现需登录才能调用接口

1.开发需要登录才能进行操作的自定义注解NeedLogin,后面可以写在需要登陆后操作的接口上

package com.songzhen.howcool.auth;

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 NeedLogin {
boolean required() default true;
}

2.开发拦截器(Interceptor),预处理全部请求

package com.songzhen.howcool.auth;

import com.alibaba.fastjson.JSON;
import com.songzhen.howcool.model.enums.RetCodeEnum;
import com.songzhen.howcool.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
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;
import java.util.HashMap;
import java.util.Map; public class AuthenticationInterceptor implements HandlerInterceptor { @Autowired
private RedisTemplate<String, String> redisTemplate; /**
* 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller
* 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception { // 判断对象是否是映射到一个方法,如果不是则直接通过
if (!(object instanceof HandlerMethod)) {
// instanceof运算符是用来在运行时指出对象是否是特定类的一个实例
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) object;
Method method = handlerMethod.getMethod();
//检查方法是否有NeedLogin注解,无则跳过认证
if (method.isAnnotationPresent(NeedLogin.class)) {
NeedLogin needLogin = method.getAnnotation(NeedLogin.class);
if (needLogin.required()) {
// 从HTTP请求头中获取TOKEN信息
String token = httpServletRequest.getHeader("Authorization"); // HTTP请求头中TOKEN解析出的用户信息
String uid = JwtUtil.getUid(token);
String userName = JwtUtil.getUserName(token);
String realName = JwtUtil.getRealName(token); // 检查TOKEN
if (!checkToken(token)) {
// TOKEN错误时,提示用户登录
Map<String, Object> retMap = new HashMap<>(16);
retMap.put("code", RetCodeEnum.ACCOUNT_UNAUTHORIZED.getCode());
retMap.put("msg", RetCodeEnum.ACCOUNT_UNAUTHORIZED.getDesc());
httpServletResponse.setContentType("application/json;charset=UTF-8");
httpServletResponse.getWriter().append(JSON.toJSONString(retMap));
return false;
} // 组装用户信息到REQUEST中
Map<String, Object> currentUser = new HashMap<>(16);
currentUser.put("uid", uid);
currentUser.put("userName", userName);
currentUser.put("realName", realName);
httpServletRequest.setAttribute("currentUser", currentUser); return true;
}
}
return true;
} /**
* 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
*/
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object, ModelAndView modelAndView) throws Exception {
long now = System.currentTimeMillis();
} /**
* 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中
*/
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
} /**
* 检查TOKEN
*
* @param token token
* 要校验的token
* @return boolean
* true:通过 false:失败
*/
private boolean checkToken(String token) {
// ------------------------认证------------开始-----------------
if (null == token) {
return false;
} // 获取TOKEN中的用户信息
String uid = JwtUtil.getUid(token); // 根据uid从redis中获取用户tokenInRedis
String tokenInRedis = redisTemplate.opsForValue().get(uid);
if (null == tokenInRedis) {
// 如果REDIS异常,返回成功保证正常业务可以继续处理
return true;
} // HTTP请求头中TOKEN解析出的用户信息
String userName = JwtUtil.getUserName(token);
String realName = JwtUtil.getRealName(token);
String deviceId = JwtUtil.getDeviceId(token);
long expireIn = JwtUtil.getExpireIn(token);
// REDIS服务器中TOKEN解析出的用户信息
String userNameInRedis = JwtUtil.getUserName(tokenInRedis);
String realNameInRedis = JwtUtil.getRealName(tokenInRedis);
String deviceIdInRedis = JwtUtil.getDeviceId(tokenInRedis);
long expireInInRedis = JwtUtil.getExpireIn(tokenInRedis); if (null == userName || null == realName || null == deviceId) {
return false;
}
if (null == userNameInRedis || null == realNameInRedis || null == deviceIdInRedis) {
return false;
}
// 判断TOKEN是否过期
if (expireIn != expireInInRedis) {
return false;
}
if (expireIn < System.currentTimeMillis()) {
return false;
}
// ------------------------认证------------结束-----------------
return true;
} }

3.开发拦截器配置类

package com.songzhen.howcool.config;

import com.songzhen.howcool.auth.AuthenticationInterceptor;
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("/**");
}
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}

4.在Controller中需要登录才能操作的方法上加上注解NeedLogin

package com.songzhen.howcool.controller;

import com.songzhen.howcool.entity.QueryUserEntity;
import com.songzhen.howcool.entity.UserLoginEntity;
import com.songzhen.howcool.auth.NeedLogin;
import com.songzhen.howcool.biz.UserBizService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest;
import java.util.Map; /**
* 用户相关.
* <p>用户相关<br>
* 用户相关
*
* @author Lucas
* @date 2018/8/9
*/
@RestController
@RequestMapping("**/v1/user")
public class UserController { private static final Logger logger = LoggerFactory.getLogger(UserController.class); @Autowired
private UserBizService userBizService; /**
* 登录
*/
@PostMapping("login")
public Map<String, Object> login(@RequestBody UserLoginEntity userLoginEntity) {
logger.info("login input params userLoginEntity={}", userLoginEntity);
return userBizService.login(userLoginEntity.getUserName(), userLoginEntity.getPassword(), userLoginEntity.getDeviceId());
} /**
* 登出
*
* @param request request
*/
@NeedLogin
@PostMapping("logout")
public Map<String, Object> logout(HttpServletRequest request) {
Map<String,Object> currentUser = (Map<String,Object>)request.getAttribute("currentUser"); return userBizService.logout(currentUser.get("uid").toString());
} /**
* 列表用户
*/
@NeedLogin
@PostMapping("pageUser")
public Map<String, Object> pageUser(@RequestBody QueryUserEntity queryUserEntity) {
logger.info("login input params queryUserEntity={}", queryUserEntity);
return userBizService.pageUsers(queryUserEntity);
} }

5.GitHub上源代码地址

https://github.com/songzhen110/howcool.git

【实战】Springboot +jjwt+注解实现需登录才能操作的更多相关文章

  1. SpringBoot版不需要配置文件注解获取当前登录用户

    本文讯(2019年3月30日 飞快的蜗牛博客)   我是一个懒人,很久不写博客,想起来看到也不一定会写,只有心血来潮的时候写写,"钱塘江上潮信来,今日方知我是我"...... 空杯 ...

  2. SpringBoot实现基于token的登录验证

    一.SpringBoot实现基于token的登录验证 基于token的登录验证实现原理:客户端通过用户名和密码调用登录接口,当验证数据库中存在该用户后,将用户的信息按照token的生成规则,生成一个字 ...

  3. Asp.Net Core 2.0 项目实战(10) 基于cookie登录授权认证并实现前台会员、后台管理员同时登录

    1.登录的实现 登录功能实现起来有哪些常用的方式,大家首先想到的肯定是cookie或session或cookie+session,当然还有其他模式,今天主要探讨一下在Asp.net core 2.0下 ...

  4. SpringBoot —— AOP注解式拦截与方法规则拦截

    AspectJ是一个面向切面的框架,它扩展了Java语言.AspectJ定义了AOP语法,所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件. SpringBoot中AOP的使用 ...

  5. 常见的springmvc、SpringBoot的注解

    springMvc的常用注解 : @Controller :用于标记在一个类上,使用它标记的类就是一个springmcv Controller对象,分发处理器将会扫描使用了该注解 的类的方法,并检测该 ...

  6. SpringBoot(14)—注解装配Bean

    SpringBoot(14)-注解装配Bean SpringBoot装配Bean方式主要有两种 通过Java配置文件@Bean的方式定义Bean. 通过注解扫描的方式@Component/@Compo ...

  7. Spring Boot 实战 —— MyBatis(注解版)使用方法

    原文链接: Spring Boot 实战 -- MyBatis(注解版)使用方法 简介 MyBatis 官网 是这么介绍它自己的: MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过 ...

  8. Springboot 拦截器配置(登录拦截)

    Springboot 拦截器配置(登录拦截) 注意这里环境为springboot为2.1版本 1.编写拦截器实现类,实现接口   HandlerInterceptor, 重写里面需要的三个比较常用的方 ...

  9. 接近8000字的Spring/SpringBoot常用注解总结!安排!

    0.前言 大家好,我是 Guide 哥!这是我的 221 篇优质原创文章.如需转载,请在文首注明地址,蟹蟹! 本文已经收录进我的 75K Star 的 Java 开源项目 JavaGuide:http ...

随机推荐

  1. codeforces 1288E. Messenger Simulator(树状数组)

    链接:https://codeforces.com/contest/1288/problem/E 题意:序列p的长度为n,初始序列为1 2 3 4 ...n,然后有m次操作,每次指定序列中一个数移动到 ...

  2. 在Vue中输入框自动获取焦点的三种方式

    原生JS操作DOM使用mounted钩子函数,它表示页面一加载进来就执行函数里面的内容(和window.onload类似)1//html部分 编号:<input type="text& ...

  3. 通过CSS禁用页面内容选中和复制操作

    -moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;-khtml-user-select: none;user ...

  4. http断点续传的原理

    ——————————————先讲原理,如下:—————————————————— 举一个详细的例子: 一般场景,要访问的域名:www.jizhuomi.com/android,文件名为down.zip ...

  5. <meta charset="utf-8" name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=2.0, user-scalable=yes"/>

    <meta charset="utf-8" name="viewport" content="width=device-width, initi ...

  6. 题解【洛谷P4588】[TJOI2018]数学计算

    题目描述 小豆现在有一个数\(x\),初始值为\(1\).小豆有\(Q\)次操作,操作有两种类型: \(1\;m\):\(x=x\times m\)输出\(x\%mod\); \(2\;pos\):\ ...

  7. 数据库程序接口——JDBC——初篇——目录

    目录 建立连接 核心对象 Driver DriverManager Connection DataSource 常用功能 第一个程序 C3P0数据源 DBCP数据源 事务之Spring事务 执行SQL ...

  8. 素问 - IC跨期套利

    摘自<小韭的学习圈> Q 我现在是长持ic.我观察到IC1907和IC1909的贴水差会有波动.有时候,IC 1907涨的多,有时候IC1909涨的多.而在某一天这个趋势相对是稳定的. 那 ...

  9. c++指针,引用,日期,输入输出和数据结构

    1,指针 指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址.就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明.指针变量声明的一般形式为: int *ip; /* ...

  10. c语言getipaddrtable获得ip地址与sendArp获得mac地址以及一些字节序问题记录

    https://docs.microsoft.com/zh-cn/windows/win32/api/iphlpapi/nf-iphlpapi-getipaddrtable msdn,有很多c的源码还 ...