Token安装

Token是一种用于验证和授权的令牌,通常用于在客户端和服务器之间进行身份验证和授权。在Web应用程序中,用户在登录后会收到一个token,这个token可以用于后续的请求中,以证明用户的身份和权限。常见的token包括JWT(JSON Web Token)和OAuth Token。Token的使用可以提高安全性,避免在每次请求时都需要重新输入用户名和密码。

在pom文件内添加依赖 添加lombok依赖,简化代码

<!--在此处加入jwt来实现token验证-->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.4.0</version>
</dependency>

<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.20</version>
    <scope>provided</scope>
</dependency>

添加两个自定义的注解 config-TokenConfig

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//添加两个自定义的注解
public class TokenConfig {

    //定义跳过token验证的注解
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface PassToken{
        boolean required() default true;
    }

    //定义需要Token验证的注解
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface UserLoginToken{
        boolean required() default true;
    }
}

在idea - file - settings - plugins 搜索lombok下载

创建工具函数来生成token密文(封装函数) utils-TokenTools

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.example.test.pojo.UserInfoPojo;

import java.util.Date;

public class TokenTools {
    //生成token密文的函数  UserInfoPojo user需要自己改
    public static String getToken(UserInfoPojo user) {
        Date start = new Date();//开始生效时间
         
        System.currentTimeMillis()方法来获取当前时间的毫秒数
        long currentTime = System.currentTimeMillis() +  60*10 * 1000;//10分钟有效时间
        long currentTime = System.currentTimeMillis() + 60*60*1000;//一小时有效时间(根据项目要求)
        Date end = new Date(currentTime); //失效时间
        //在这里使用了用户的id和密码以生成一个token
        String token = JWT.create().withAudience(user.getId().toString()).withIssuedAt(start).withExpiresAt(end)
                .sign(Algorithm.HMAC256(user.getPassword()));
        return token;
    }
}

创建拦截器函数(在访问功能函数前,会检查是否有token注解,有则验证,无则跳过验证) config-AuthenticationInterceptor

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.example.test.pojo.UserInfoPojo;
import com.example.test.service.frontservice.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
    private UserService userService;

    @Override
    //prehandle函数会在Controller里的函数被调用之前提前调用
    //所以在这里可以达到提前拦截的效果
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // 从 http 请求头中取出 token
        String token = request.getHeader("token");
        // 如果不是映射到方法直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();//获取到被注解的函数
        //检查函数是否有@PassToken注解,有则直接跳过认证
        if (method.isAnnotationPresent(TokenConfig.PassToken.class)) {
            TokenConfig.PassToken passToken = method.getAnnotation(TokenConfig.PassToken.class);
            if (passToken.required()) {
                return true;
            }
        }

        //检查函数是否有UserLoginToken注解, 有则执行验证, 无则执行return true
        if (method.isAnnotationPresent(TokenConfig.UserLoginToken.class)) {
            TokenConfig.UserLoginToken userLoginToken = method.getAnnotation(TokenConfig.UserLoginToken.class);
            if (userLoginToken.required()) {
                // 执行认证
                if (token == null) {
                    throw new RuntimeException("当前无token信息,请重新登录!");
                }
                // 获取 token 中的 userId
                String userId;
                try {
                    userId = JWT.decode(token).getAudience().get(0);
                } catch (JWTDecodeException j) {
                    throw new RuntimeException("Token获取失败或有误!");
                }

                //通过token中的userId来验证是否存在 验证用户名是否重复 userId
                //需要自己改 userService.findUserById(userId)
                UserInfoPojo up = userService.findUserById(userId);
                if (up == null) {
                    throw new RuntimeException("当前用户ID不存在,请重新登录!");
                }

                // 通过token中的password与最新查询到password对比 来验证token的正确性
                //up.getPassword()需要自己改
                JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256( up.getPassword() )).build();
                try {
                    jwtVerifier.verify(token); // 密码 / 时间
                } catch (JWTVerificationException e) {
                    throw new RuntimeException("Token获取失败或已过期!");
                }

                return true;

            }
        }

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object o, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object o, Exception e) throws Exception {
    }

}

添加拦截器函数的配置文件(设定拦截的访问路径范围) interceptor-InterceptorConfig

interceptor与controller同级

import com.example.test.config.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();
    }
}

创建两个pojo实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class JsonMsgPojo {
    private boolean status;
    private String msg;
    private Object data;
}

UserPojo人员信息实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserPojo {
    private Long id;
    private String un;
    private String pw;
    private String token;
}

创建登录函数

@PostMapping("login")
public JsonMsgPojo login(UserPojo up){
    UserPojo userPojo = userService.login(up);
    if (userPojo==null){
        return new JsonMsgPojo(false,"用户名或密码错误!",null);
    }
    return new JsonMsgPojo(true,"登陆成功!",userPojo);
}

创建根据id查询用户的函数

@GetMapping("findUserById")
public JsonMsgPojo findUserById(UserPojo up){
    UserPojo userPojo = userService.findUserById(up);
    if (userPojo == null){
        return new JsonMsgPojo(false,"用户不存在!",null);
    }
    return new JsonMsgPojo(true,"查询成功!",null);
}

测试token功能

@PostMapping("login")
public JsonMsgPojo login(UserPojo up){
    UserPojo userPojo = userService.login(up);
    if (userPojo==null){
        return new JsonMsgPojo(false,"用户名或密码错误!",null);
    }
    String token = TokenTools.getToken(userPojo);
    userPojo.setToken(token);
    return new JsonMsgPojo(true,"登陆成功!",userPojo);
}

 携带token访问需要token验证的函数

@TokenConfig.UserLoginToken
    @ResponseBody
    @GetMapping("userCheck")
    public JSONMsgPojo userCheck(long id){
        return  userService.userCheck(id);
    }

 token时间失效后需要重新登录,否则访问失败

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值