springboot整合jwt_springboot整合jwt实现身份验证

一.JWT简介

1.简介

JSON Web token简称JWT, 是用于对应用程序上的用户进行身份验证的标记。也就是说, 使用 JWTS 的应用程序不再需要保存有关其用户的 cookie 或其他session数据。此特性便于可伸缩性, 同时保证应用程序的安全。
在身份验证过程中, 当用户使用其凭据成功登录时, 将返回 JSON Web token, 并且必须在本地保存 (通常在本地存储中)。每当用户要访问受保护的路由或资源 (端点) 时, 用户代理(user agent)必须连同请求一起发送 JWT, 通常在授权标头中使用Bearer schema。后端服务器接收到带有 JWT 的请求时, 首先要做的是验证token。

2.JWT的格式

JWT就是一个字符串,经过加密处理与校验处理的字符串,形式为:A.B.C
A由JWT头部信息header加密得到
B由JWT用到的身份验证信息json数据加密得到
C由A和B加密得到,是校验部分

3.怎样使用token?

可以放到HTTP请求的请求头中,通常是Authorization字段。

4.流程图

f5d9cdebe90f7100b3c20fb951083ba3.png

二.maven依赖

org.springframework.boot            spring-boot-starter-web        org.springframework.boot            spring-boot-starter-test            testio.jsonwebtoken            jjwt            0.9.0com.alibaba            fastjson            1.2.58javax.xml.bind            jaxb-api            2.3.0javax.servlet            javax.servlet-api            4.0.1三.代码部分1.application.propertiesserver.port=8087# 加密yanjwt.secret=A0B1C2D3E4F5G6H7I8J9KALBMCNDOEPFQ0R1S2T3U4V5W6X7Y8Z9# tocken 过期时间,单位秒jwt.expire=300# 需要认证的url,多个URL使用英文逗号,分割jwt.authorised-urls=/api/**2.建立config包,并在包下面建立JwtConfig类和JwtFilter类import java.util.ArrayList;import java.util.List;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.web.servlet.FilterRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class JwtConfig {    @Value("${jwt.secret}")    private String secret;    @Value("${jwt.expire}")    private long expire;    @Value("${jwt.authorised-urls}")    private String[] authorisedUrls;    @Bean    public JwtHelper jwtHelperBean() {        return new JwtHelper(secret, expire);    }    @Bean    public FilterRegistrationBean basicFilterRegistrationBean() {        FilterRegistrationBean registrationBean = new FilterRegistrationBean();        JwtFilter filter = new JwtFilter(jwtHelperBean(), authorisedUrls);        registrationBean.setFilter(filter);        List urlPatterns = new ArrayList();        urlPatterns.add("/*");        registrationBean.setUrlPatterns(urlPatterns);        return registrationBean;    }}import java.io.IOException;import java.util.Arrays;import java.util.List;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.http.HttpStatus;import org.springframework.util.AntPathMatcher;/** * JWT过滤器 */public class JwtFilter implements Filter {    private JwtHelper jwtHelper;    private List urls = null;    private static final org.springframework.util.PathMatcher pathMatcher = new AntPathMatcher();    public JwtFilter(JwtHelper jwtHelper, String[] authorisedUrls) {        this.jwtHelper = jwtHelper;        urls = Arrays.asList(authorisedUrls);    }    @Override    public void init(FilterConfig filterConfig) throws ServletException {        //SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, filterConfig.getServletContext());    }    @Override    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {        HttpServletRequest httpRequest = (HttpServletRequest) request;        HttpServletResponse httpResponse = (HttpServletResponse) response;        httpResponse.setCharacterEncoding("UTF-8");        httpResponse.setContentType("application/json; charset=utf-8");        httpResponse.setHeader("Access-Control-Allow-Origin", "*");        if ("OPTIONS".equals(httpRequest.getMethod())) {            httpResponse.setStatus(HttpStatus.NO_CONTENT.value()); // HttpStatus.SC_NO_CONTENT = 204            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");            httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, x-requested-with, Token");            httpResponse.setHeader("Access-Control-Allow-Methods", "OPTIONS,GET,POST,DELETE,PUT");        }        String spath = httpRequest.getServletPath();        /*try {            // 验证受保护的接口            for (String url : urls) {                if (pathMatcher.match(url, spath)) {                    Object token = jwtHelper.validateTokenAndGetClaims(httpRequest);                    if (token != null) {                        chain.doFilter(request, response);                        return;                    }else{                        httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "未授权或者授权已经过期");                        return;                    }                }else{                    chain.doFilter(request, response);                    return;                }            }        } catch (Exception e) {            e.printStackTrace();        }*/        // 验证受保护的接口        for (String url : urls) {            if (pathMatcher.match(url, spath)) {                Object token = jwtHelper.validateTokenAndGetClaims(httpRequest);                 HttpSession session = httpRequest.getSession();                session.setAttribute("loginName", ((Map) token).get("loginName"));          //将用户名放在session中                if (token != null) {                    chain.doFilter(request, response);                    return;                }else{                    httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "未授权或者授权已经过期");                    return;                }            }else{                chain.doFilter(request, response);                return;            }        }        chain.doFilter(request, response);        return;    }    @Override    public void destroy() {    }}3.建立Util工具包,并在包下建立JwtHelper工具类和JsonResult工具类import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date;import java.util.Map;import javax.servlet.http.HttpServletRequest;import com.alibaba.fastjson.JSONObject;import io.jsonwebtoken.Jwts;import io.jsonwebtoken.SignatureAlgorithm;public class JwtHelper {    private Long EXPIRATION_TIME;    private String SECRET;    private final String TOKEN_PREFIX = "Bearer";    private final String HEADER_STRING = "Authorization";    public JwtHelper(String secret, long expire) {        this.EXPIRATION_TIME = expire;        this.SECRET = secret;        System.out.println("正在初始化Jwthelper,expire="+expire);    }    public JSONObject generateToken(Map claims) {        Calendar c = Calendar.getInstance();        c.setTime(new Date());        c.add(Calendar.SECOND, EXPIRATION_TIME.intValue());        Date d = c.getTime();        String jwt = Jwts.builder()                .setClaims(claims)                .setExpiration(d)                .signWith(SignatureAlgorithm.HS512, SECRET)                .compact();        JSONObject json = new JSONObject();        json.put("token",TOKEN_PREFIX + " " + jwt);        json.put("token-type", TOKEN_PREFIX);        json.put("expire-time",new SimpleDateFormat("yyyy-MM-dd HH:ss:mm").format(d) );        return json;    }    public Map validateTokenAndGetClaims(HttpServletRequest request) {        String token = request.getHeader(HEADER_STRING);        System.out.println("token is:"+token);        if (token == null) {            return null;        }        Map body = Jwts.parser()                .setSigningKey(SECRET)                .parseClaimsJws(token.replace(TOKEN_PREFIX, ""))                .getBody();        return body;    }}import com.alibaba.fastjson.JSONObject;public class JsonResult {    public static JSONObject success(Object obj) {        JSONObject json = new JSONObject();        json.put("status", 200);        json.put("message", "成功");        if (null != obj) {            json.put("obj", obj);        }        return json;    }    public static JSONObject fail(Object obj) {        JSONObject json = new JSONObject();        json.put("status", 200);        json.put("message", "失败");        if (null != obj) {            json.put("obj", obj);        }        return json;    }    public static JSONObject toJSONObject(Integer status, String msg, Object obj) {        JSONObject json = new JSONObject();        json.put("status", status);        json.put("message", msg);        if (null != obj) {            json.put("obj", obj);        }        return json;    }}4.建立controller包,并在包下建立AuthorizeController类和TestController类import java.util.HashMap;import java.util.Map;import io.jsonwebtoken.ExpiredJwtException;import io.jsonwebtoken.MalformedJwtException;import io.jsonwebtoken.SignatureException;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/auth")public class AuthorizeController {    @Autowired    private JwtHelper jwtHelper;    @PostMapping("/login")    public Object login(String loginName,String password) {        Map claims = new HashMap();        claims.put("loginName", loginName);        if ("1".equals(password)) {            return JsonResult.success(jwtHelper.generateToken(claims));        } else {            return JsonResult.fail("登录帐号或者登录密码错误");        }    }}import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/api/test")public class TestController {    @PostMapping("/hello")    public String hello(String id) {        return "hello";    }}5.全局异常处理建立ControllerException类来捕获各类异常,再返回给前端import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.web.servlet.error.ErrorAttributes;import org.springframework.boot.web.servlet.error.ErrorController;import org.springframework.http.MediaType;import org.springframework.web.bind.annotation.*;import org.springframework.web.context.request.ServletWebRequest;import org.springframework.web.context.request.WebRequest;import javax.servlet.http.HttpServletRequest;import java.util.Map;@RestControllerpublic class ControllerException implements ErrorController {    private final String PATH = "/error";    @Autowired    private ErrorAttributes errorAttributes;    @Override    public String getErrorPath() {        return PATH;    }    @RequestMapping(value = PATH, produces = {MediaType.APPLICATION_JSON_VALUE})    public Object handlerError(HttpServletRequest request){        Map attributesMap = getErrorAttributes(request, true);        System.out.println(attributesMap.get("message"));        String msg = null;        if (attributesMap.get("message").toString().indexOf("JWT expired") != -1) msg = "JWT已过期";        else if (attributesMap.get("message").toString().indexOf("JWT strings must contain exactly 2 period characters") != -1) msg = "JWT格式错误";        else if(attributesMap.get("message").toString().indexOf("No message available") != -1) msg = "参数值缺失";        else msg = attributesMap.get("message").toString();        return JsonResult.toJSONObject(Integer.parseInt(attributesMap.get("status").toString()), msg, attributesMap.get("message"));    }    protected Map getErrorAttributes(HttpServletRequest request, boolean includeStackTrace){        WebRequest webRequest = new ServletWebRequest(request);        return this.errorAttributes.getErrorAttributes(webRequest, includeStackTrace);    }}作者:寻找大海的鱼链接:https://www.jianshu.com/p/e0b2ea66c94c来源:简书著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

代码部分

三.代码部分

1.application.properties

server.port=8087# 加密yanjwt.secret=A0B1C2D3E4F5G6H7I8J9KALBMCNDOEPFQ0R1S2T3U4V5W6X7Y8Z9# tocken 过期时间,单位秒jwt.expire=300# 需要认证的url,多个URL使用英文逗号,分割jwt.authorised-urls=/api/**

2.建立config包,并在包下面建立JwtConfig类和JwtFilter类

import java.util.ArrayList;import java.util.List;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.web.servlet.FilterRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class JwtConfig {    @Value("${jwt.secret}")    private String secret;    @Value("${jwt.expire}")    private long expire;    @Value("${jwt.authorised-urls}")    private String[] authorisedUrls;    @Bean    public JwtHelper jwtHelperBean() {        return new JwtHelper(secret, expire);    }    @Bean    public FilterRegistrationBean basicFilterRegistrationBean() {        FilterRegistrationBean registrationBean = new FilterRegistrationBean();        JwtFilter filter = new JwtFilter(jwtHelperBean(), authorisedUrls);        registrationBean.setFilter(filter);        List urlPatterns = new ArrayList();        urlPatterns.add("/*");        registrationBean.setUrlPatterns(urlPatterns);        return registrationBean;    }}
import java.io.IOException;import java.util.Arrays;import java.util.List;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.http.HttpStatus;import org.springframework.util.AntPathMatcher;/** * JWT过滤器 */public class JwtFilter implements Filter {    private JwtHelper jwtHelper;    private List urls = null;    private static final org.springframework.util.PathMatcher pathMatcher = new AntPathMatcher();    public JwtFilter(JwtHelper jwtHelper, String[] authorisedUrls) {        this.jwtHelper = jwtHelper;        urls = Arrays.asList(authorisedUrls);    }    @Override    public void init(FilterConfig filterConfig) throws ServletException {        //SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, filterConfig.getServletContext());    }    @Override    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {        HttpServletRequest httpRequest = (HttpServletRequest) request;        HttpServletResponse httpResponse = (HttpServletResponse) response;        httpResponse.setCharacterEncoding("UTF-8");        httpResponse.setContentType("application/json; charset=utf-8");        httpResponse.setHeader("Access-Control-Allow-Origin", "*");        if ("OPTIONS".equals(httpRequest.getMethod())) {            httpResponse.setStatus(HttpStatus.NO_CONTENT.value()); // HttpStatus.SC_NO_CONTENT = 204            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");            httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, x-requested-with, Token");            httpResponse.setHeader("Access-Control-Allow-Methods", "OPTIONS,GET,POST,DELETE,PUT");        }        String spath = httpRequest.getServletPath();        /*try {            // 验证受保护的接口            for (String url : urls) {                if (pathMatcher.match(url, spath)) {                    Object token = jwtHelper.validateTokenAndGetClaims(httpRequest);                    if (token != null) {                        chain.doFilter(request, response);                        return;                    }else{                        httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "未授权或者授权已经过期");                        return;                    }                }else{                    chain.doFilter(request, response);                    return;                }            }        } catch (Exception e) {            e.printStackTrace();        }*/        // 验证受保护的接口        for (String url : urls) {            if (pathMatcher.match(url, spath)) {                Object token = jwtHelper.validateTokenAndGetClaims(httpRequest);                 HttpSession session = httpRequest.getSession();                session.setAttribute("loginName", ((Map) token).get("loginName"));          //将用户名放在session中                if (token != null) {                    chain.doFilter(request, response);                    return;                }else{                    httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "未授权或者授权已经过期");                    return;                }            }else{                chain.doFilter(request, response);                return;            }        }        chain.doFilter(request, response);        return;    }    @Override    public void destroy() {    }}

3.建立Util工具包,并在包下建立JwtHelper工具类和JsonResult工具类

import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date;import java.util.Map;import javax.servlet.http.HttpServletRequest;import com.alibaba.fastjson.JSONObject;import io.jsonwebtoken.Jwts;import io.jsonwebtoken.SignatureAlgorithm;public class JwtHelper {    private Long EXPIRATION_TIME;    private String SECRET;    private final String TOKEN_PREFIX = "Bearer";    private final String HEADER_STRING = "Authorization";    public JwtHelper(String secret, long expire) {        this.EXPIRATION_TIME = expire;        this.SECRET = secret;        System.out.println("正在初始化Jwthelper,expire="+expire);    }    public JSONObject generateToken(Map claims) {        Calendar c = Calendar.getInstance();        c.setTime(new Date());        c.add(Calendar.SECOND, EXPIRATION_TIME.intValue());        Date d = c.getTime();        String jwt = Jwts.builder()                .setClaims(claims)                .setExpiration(d)                .signWith(SignatureAlgorithm.HS512, SECRET)                .compact();        JSONObject json = new JSONObject();        json.put("token",TOKEN_PREFIX + " " + jwt);        json.put("token-type", TOKEN_PREFIX);        json.put("expire-time",new SimpleDateFormat("yyyy-MM-dd HH:ss:mm").format(d) );        return json;    }    public Map validateTokenAndGetClaims(HttpServletRequest request) {        String token = request.getHeader(HEADER_STRING);        System.out.println("token is:"+token);        if (token == null) {            return null;        }        Map body = Jwts.parser()                .setSigningKey(SECRET)                .parseClaimsJws(token.replace(TOKEN_PREFIX, ""))                .getBody();        return body;    }}
import com.alibaba.fastjson.JSONObject;public class JsonResult {    public static JSONObject success(Object obj) {        JSONObject json = new JSONObject();        json.put("status", 200);        json.put("message", "成功");        if (null != obj) {            json.put("obj", obj);        }        return json;    }    public static JSONObject fail(Object obj) {        JSONObject json = new JSONObject();        json.put("status", 200);        json.put("message", "失败");        if (null != obj) {            json.put("obj", obj);        }        return json;    }    public static JSONObject toJSONObject(Integer status, String msg, Object obj) {        JSONObject json = new JSONObject();        json.put("status", status);        json.put("message", msg);        if (null != obj) {            json.put("obj", obj);        }        return json;    }}

4.建立controller包,并在包下建立AuthorizeController类和TestController类

import java.util.HashMap;import java.util.Map;import io.jsonwebtoken.ExpiredJwtException;import io.jsonwebtoken.MalformedJwtException;import io.jsonwebtoken.SignatureException;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/auth")public class AuthorizeController {    @Autowired    private JwtHelper jwtHelper;    @PostMapping("/login")    public Object login(String loginName,String password) {        Map claims = new HashMap();        claims.put("loginName", loginName);        if ("1".equals(password)) {            return JsonResult.success(jwtHelper.generateToken(claims));        } else {            return JsonResult.fail("登录帐号或者登录密码错误");        }    }}
import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/api/test")public class TestController {    @PostMapping("/hello")    public String hello(String id) {        return "hello";    }}

5.全局异常处理

建立ControllerException类来捕获各类异常,再返回给前端

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.web.servlet.error.ErrorAttributes;import org.springframework.boot.web.servlet.error.ErrorController;import org.springframework.http.MediaType;import org.springframework.web.bind.annotation.*;import org.springframework.web.context.request.ServletWebRequest;import org.springframework.web.context.request.WebRequest;import javax.servlet.http.HttpServletRequest;import java.util.Map;@RestControllerpublic class ControllerException implements ErrorController {    private final String PATH = "/error";    @Autowired    private ErrorAttributes errorAttributes;    @Override    public String getErrorPath() {        return PATH;    }    @RequestMapping(value = PATH, produces = {MediaType.APPLICATION_JSON_VALUE})    public Object handlerError(HttpServletRequest request){        Map attributesMap = getErrorAttributes(request, true);        System.out.println(attributesMap.get("message"));        String msg = null;        if (attributesMap.get("message").toString().indexOf("JWT expired") != -1) msg = "JWT已过期";        else if (attributesMap.get("message").toString().indexOf("JWT strings must contain exactly 2 period characters") != -1) msg = "JWT格式错误";        else if(attributesMap.get("message").toString().indexOf("No message available") != -1) msg = "参数值缺失";        else msg = attributesMap.get("message").toString();        return JsonResult.toJSONObject(Integer.parseInt(attributesMap.get("status").toString()), msg, attributesMap.get("message"));    }    protected Map getErrorAttributes(HttpServletRequest request, boolean includeStackTrace){        WebRequest webRequest = new ServletWebRequest(request);        return this.errorAttributes.getErrorAttributes(webRequest, includeStackTrace);    }}


四.测试

5038a1862aa7b6c4cebd71176b1dc1c2.png

2.访问需要授权的url

77983e4b48bf31d3da01fe24a5b0cd15.png

3.将步骤1的token放到header里面的Authorization参数里面

d81e8690093b0c07bc01e3b5d8e6fb7c.png

访问成功

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值