zoukankan      html  css  js  c++  java
  • springboot之JWT实现权限认证

    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 {
        }
    }
    View Code

    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
    
    返回参数:你已通过验证
  • 相关阅读:
    【BZOJ】1710: [Usaco2007 Open]Cheappal 廉价回文
    【BZOJ】3302: [Shoi2005]树的双中心 && 2103: Fire 消防站 && 2447: 消防站
    【BZOJ】1706: [usaco2007 Nov]relays 奶牛接力跑
    【Atcoder】CODE FESTIVAL 2017 qual A D
    【BZOJ】3038: 上帝造题的七分钟2 && 3211: 花神游历各国
    【BZOJ】1707: [Usaco2007 Nov]tanning分配防晒霜
    【BZOJ】1754: [Usaco2005 qua]Bull Math
    【BZOJ】1584: [Usaco2009 Mar]Cleaning Up 打扫卫生
    【BZOJ】1828: [Usaco2010 Mar]balloc 农场分配(经典贪心)
    【BZOJ】1709: [Usaco2007 Oct]Super Paintball超级弹珠
  • 原文地址:https://www.cnblogs.com/ywjfx/p/11302361.html
Copyright © 2011-2022 走看看