Spring 中的 Token 验证

本文介绍了在Java Web项目中,使用Token进行身份验证的方法,作为替代传统session的高级策略。Token提供了更好的安全性,并具有更好的兼容性。主要内容包括Token验证的基本流程:用户登录,后台验证,生成jwt字符串存入cookie,前端请求时在http header中添加Authorization字段,后台过滤器进行jwt验证。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在 Java Web 工程项目中,登录等操作是非常常见的,那么登陆之后要做的第一件事就是要记住这个登录状态,那么常规且一般的操作是怎么做的呢?

1.账号密码验证

2.验证通过,往 session 里赛用户信息

但是今天要介绍另一个高级的身份验证方法 : token

那么为什么要使用 token 而不直接使用 session 呢?首先,token 相对session安全性更好,另外这种方法兼容性更高

那么来讲讲 Token 的基本流程

1.用户输入登录信息

2.后台获取登录信息并且验证账号密码正确

3.后台取用户 id 通过 Jwt 的算法得出一个 jwt 字符串

4.后台往 cookie 里放入 jwt

5.前台收到cookie 之后,在后面的访问操作里要在 http header 里加入 Authorization : token

6.后台过滤器过滤需要验证的请求,在请求里找 Authorization 信息,提取出来后做 jwt 验证,未过期则可访问

 

JwtUtil.java

 

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JwtUtil {
    static final String SECRET = "ThisIsASecret";

    public static String generateToken(String username) {
        HashMap<String, Object> map = new HashMap<>();
        //you can put any data in the map
        map.put("username", username);
        String jwt = Jwts.builder()
                .setClaims(map)
                .setExpiration(new Date(System.currentTimeMillis() + 86_400_000L))// 24 hour 86400000 ms
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .compact();
        return "Bearer "+jwt; //jwt前面一般都会加Bearer
    }

    public static void validateToken(String token) {
        try {
            // parse the token.
            Map<String, Object> body = Jwts.parser()
                    .setSigningKey(SECRET)
                    .parseClaimsJws(token.replace("Bearer ",""))
                    .getBody();
            for (Object value : body.values()) {
                System.out.println("Value = " + value);
            }
        }catch (Exception e){
            throw new IllegalStateException("Invalid Token. "+e.getMessage());
        }
    }
}

JwtAuthenticationFilter.java

 

import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLDecoder;


public class JwtAuthenticationFilter extends OncePerRequestFilter {
    private static final PathMatcher pathMatcher = new AntPathMatcher();

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            if(isProtectedUrl(request)) {
                String token = request.getHeader("Authorization");
                token = URLDecoder.decode(token);
                System.out.println("token = " + token);
                //检查jwt令牌, 如果令牌不合法或者过期, 里面会直接抛出异常, 下面的catch部分会直接返回
                JwtUtil.validateToken(token);
            }
        } catch (Exception e) {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
            return;
        }
        //如果jwt令牌通过了检测, 那么就把request传递给后面的RESTful api
        filterChain.doFilter(request, response);
    }


    //我们只对地址 /api 开头的api检查jwt. 不然的话登录/login也需要jwt
    private boolean isProtectedUrl(HttpServletRequest request) {
        return pathMatcher.match("/*/token/*", request.getServletPath());
    }

}

AdminController.java

 

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

@Controller
@RequestMapping("/admin")
public class AdminController {
    @Resource
    private AdminService adminService;

    @RequestMapping("/login")
    public ModelAndView login(HttpSession session, HttpServletRequest request, HttpServletResponse response) throws IOException{
        ModelAndView mv = new ModelAndView();
        String adminId = request.getParameter("adminId");
        String pwd = request.getParameter("pwd");
        Admin admin = adminService.Login(adminId,pwd);
        if(admin != null){
            String jwt = JwtUtil.generateToken(admin.getAdminId());
            jwt = URLEncoder.encode(jwt);
            Cookie cookie_token = new Cookie("token",jwt);
            cookie_token.setMaxAge(60*60*60);
            cookie_token.setPath("/");
            response.addCookie(cookie_token);
            mv.addObject("admin",admin);
            mv.setViewName("adminPage");
        }else{
            mv.setViewName("index");
        }

        return mv;
    }
    @RequestMapping("/token/logout")
    @ResponseBody
    public Map logout(HttpSession session, HttpServletRequest request, HttpServletResponse response)throws IOException{
        Map<String,Object> result = new HashMap<>();
        session.invalidate();
        Cookie cookie_token = new Cookie("token",null);
        cookie_token.setMaxAge(0);
        cookie_token.setPath("/");
        response.addCookie(cookie_token);
        result.put("msg","退出成功");
        result.put("status",true);
        return result;
    }
    @ResponseBody
    @RequestMapping("/token/show")
    public Map show(HttpSession session, HttpServletRequest request, HttpServletResponse response) throws IOException{
        Map<String,Object> result = new HashMap<>();
        result.put("status",true);
        result.put("msg","ok");
        return result;
    }

}

前端发送 ajax 添加 header

 

<script>
    function test() {
        var token = getCookie("token");
        var data = {
            hi:"hello"
        };
        $.ajax({
            url:"/admin/token/show",
            data:data,
            type:"post",
            cache:false,
            dataType:"json",
            success :function (data) {
                alert(data.msg);
            },
            beforeSend: function(xhr) {
                xhr.setRequestHeader("Authorization", token);
            },
            error : function (data) {
                alert("请求超时");
            }
        })
    }
    function test2() {
        var token = getCookie("token");
        var data = {
            hi:"hello"
        };
        $.ajax({
            url:"/admin/token/logout",
            data:data,
            type:"post",
            cache:false,
            dataType:"json",
            success :function (data) {
                alert(data.msg);
            },
            beforeSend: function(xhr) {
                xhr.setRequestHeader("Authorization", token);
            },
            error : function (data) {
                alert("请求超时");
            }
        })
    }
    function getCookie(key) {
        var cookieArr = document.cookie.split('; ');
        for(var i = 0; i < cookieArr.length; i++) {
            var arr = cookieArr[i].split('=');
            if(arr[0] === key) {
                return arr[1];
            }
        }
        return false;
    }
</script>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值