springboot+jwt实现token验证

项目结构
在这里插入图片描述
1.导入pom依赖

<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.2</version>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.47</version>
		</dependency>

		<!---->
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt</artifactId>
			<version>0.9.1</version>
		</dependency>
		<dependency>
			<groupId>com.auth0</groupId>
			<artifactId>java-jwt</artifactId>
			<version>3.4.0</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.37</version>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>commons-codec</groupId>
			<artifactId>commons-codec</artifactId>
			<version>1.10</version>
		</dependency>
	</dependencies>

2.application.properties配置

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test2
spring.datasource.username=root
spring.datasource.password=root

mybatis.mapper-locations=classpath:mapper/*.xml

3.用户对应数据库的实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    String Id;
    String username;
    String password;
}

4.dao层

public interface UserMapper {
    User findByUsername(@Param("username") String username);
}

不要忘了在主启动类上加接口扫描 @MapperScan(“com.cn.dao”)

5.创建UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="com.cn.dao.UserMapper">
    <select id="findByUsername" resultType="com.cn.entity.User">
      SELECT * FROM user
      where
      username=#{username}
    </select>
</mapper>

6.service层

public interface UserService {
    User findByUsername(String username);
}
@Service
public class UserServiceImpl implements UserService{
    @Autowired
    private UserMapper userMapper;
    @Override
    public User findByUsername(String username) {
        return userMapper.findByUsername(username);
    }
}

7.创建token生成类

//生成token的类
@Service
public class CreateTokenService {
    public String createToken(User user){
        String token= JWT.create().withAudience(user.getUsername())
                .withExpiresAt(new Date(System.currentTimeMillis()+1000*30))//token失效的时间  这里我设置的是30秒失效
                .withNotBefore(new Date())     //token开始生效的时间
                .sign(Algorithm.HMAC256(user.getPassword()));
        return token;
    }
}

8.jwt配置
token是否验证自定义注解

//controller中不需要token验证的方法则用次注解  默认不许要验证
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
    boolean required() default true;
}
//controller中需要token验证的方法则用次注解  默认许要验证
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidateToken {
    boolean required() default true;
}

方法预处理

//在次拦截  处理token
public class AuthenticationInterceptor implements HandlerInterceptor{

    @Resource
    private UserService userService;
    //进入controller方法之前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token=request.getHeader("token");//从http的请求头中取出

        //如果不上方法则跳过
        if (!(handler instanceof HandlerMethod)){
            return true;
        }

        HandlerMethod handlerMethod=(HandlerMethod) handler;
        Method method=handlerMethod.getMethod();

        //如果controller这个方法上面有这个 @PassToken 注解  返回 true 不需要token验证放行
        if (method.isAnnotationPresent(PassToken.class)){
            PassToken passToken=method.getAnnotation(PassToken.class);
            if (passToken.required()){
                return true;
            }
        }

        //如果controller这个方法上面有这个 @ValidateToken 注解  返回 true token合格  否则token不合格教由全局异常处理
        if (method.isAnnotationPresent(ValidateToken.class)){
            ValidateToken validateToken=method.getAnnotation(ValidateToken.class);
            if (validateToken.required()){
                //开始token校验
                if (token==null){
                    throw new RuntimeException("请求头中没有token");
                }
                //取出创建token时塞入的用户名
                String username;
                try {
                    username=JWT.decode(token).getAudience().get(0);
                } catch (JWTDecodeException e) {
                    throw new RuntimeException("解析token异常");
                }

                User user=userService.findByUsername(username);
                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("token已过期请重新登录");
                }
                return true;
            }
        }
        return true;
    }

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

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {

    }
}

拦截器配置

@Configuration
public class InterceptorConfig implements WebMvcConfigurer{
    // 拦截所有请求,通过判断是否有 @VilidateToken 注解 决定是否需要登录
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authenticationInterceptor()).addPathPatterns("/**");
    }

    @Bean
    public AuthenticationInterceptor authenticationInterceptor(){
        return new AuthenticationInterceptor();
    }
}

9.全局异常处理友好返回前端配置

//全局异常处理类  处理异常信息  友好地返回前台
@ControllerAdvice
public class GloabException {

    @ResponseBody
    @ExceptionHandler(Exception.class)
    public String excetptionMsg(Exception e, HttpServletResponse response, HttpServletRequest request){
        //解决跨域问题
        response.setHeader("Access-Control-Allow-Origin","*");
        //取出异常信息
        String errorMsg=e.getMessage();
        if (errorMsg!=null){
            JSONObject jsonObject= new JSONObject();
            jsonObject.put("errorMsg",errorMsg);
            return jsonObject.toJSONString();
        }
        return null;
    }
}

10.controller

@RestController
@RequestMapping("/user")
public class UserController {
    @Resource
    private UserService userService;

    @Resource
    private CreateTokenService createTokenService;

    //用户登录
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public Object login(@RequestBody User user){
        JSONObject jsonObject=new JSONObject();
        User user1=userService.findByUsername(user.getUsername());
        if (user1!=null){
            if (user1.getPassword().equals(user.getPassword())){
                String token=createTokenService.createToken(user);
                jsonObject.put("token",token);
                jsonObject.put("user",user1);
                jsonObject.put("msg","登录成功");
                return jsonObject;
            }else {
                jsonObject.put("errorMsg","用户密码不正确");
                return jsonObject;
            }
        }else {
            jsonObject.put("errorMsg","用户不存在");
            return jsonObject;
        }
    }

    //测试token是否生效
    @ValidateToken//添加token验证  不加默认不验证
    @RequestMapping(value = "/testToken",method = RequestMethod.GET)
    public Object testToken(){
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("msg","token配置生效");
        return jsonObject;
    }
}

10.启动项目 使用postman测试
登录
在这里插入图片描述
token验证

token有效时间内(我只给了它30s有效)
在这里插入图片描述
token已过期
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值