[转] Spring Boot实战之Filter实现使用JWT进行接口认证
【From】 http://blog.csdn.net/sun_t89/article/details/51923017
Spring Boot实战之Filter实现使用JWT进行接口认证
jwt(json web token)
用户发送按照约定,向服务端发送 Header、Payload 和 Signature,并包含认证信息(密码),验证通过后服务端返回一个token,之后用户使用该token作为登录凭证,适合于移动端和api
jwt使用流程
本文示例接上面几篇文章中的代码进行编写,请阅读本文的同时可以参考前面几篇文章
1、添加依赖库jjwt,本文中构造jwt及解析jwt都使用了jjwt库
- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt</artifactId>
- <version>0.6.0</version>
- </dependency>
2、添加登录获取token时,所需要的认证信息类LoginPara.java
- package com.xiaofangtech.sunt.jwt;
- public class LoginPara {
- private String clientId;
- private String userName;
- private String password;
- private String captchaCode;
- private String captchaValue;
- public String getClientId() {
- return clientId;
- }
- public void setClientId(String clientId) {
- this.clientId = clientId;
- }
- public String getUserName() {
- return userName;
- }
- public void setUserName(String userName) {
- this.userName = userName;
- }
- public String getPassword() {
- return password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
- public String getCaptchaCode() {
- return captchaCode;
- }
- public void setCaptchaCode(String captchaCode) {
- this.captchaCode = captchaCode;
- }
- public String getCaptchaValue() {
- return captchaValue;
- }
- public void setCaptchaValue(String captchaValue) {
- this.captchaValue = captchaValue;
- }
- }
3、添加构造jwt及解析jwt的帮助类JwtHelper.java
- package com.xiaofangtech.sunt.jwt;
- import java.security.Key;
- import java.util.Date;
- import javax.crypto.spec.SecretKeySpec;
- import javax.xml.bind.DatatypeConverter;
- import io.jsonwebtoken.Claims;
- import io.jsonwebtoken.JwtBuilder;
- import io.jsonwebtoken.Jwts;
- import io.jsonwebtoken.SignatureAlgorithm;
- public class JwtHelper {
- public static Claims parseJWT(String jsonWebToken, String base64Security){
- try
- {
- Claims claims = Jwts.parser()
- .setSigningKey(DatatypeConverter.parseBase64Binary(base64Security))
- .parseClaimsJws(jsonWebToken).getBody();
- return claims;
- }
- catch(Exception ex)
- {
- return null;
- }
- }
- public static String createJWT(String name, String userId, String role,
- String audience, String issuer, long TTLMillis, String base64Security)
- {
- SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
- long nowMillis = System.currentTimeMillis();
- Date now = new Date(nowMillis);
- //生成签名密钥
- byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(base64Security);
- Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
- //添加构成JWT的参数
- JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
- .claim("role", role)
- .claim("unique_name", name)
- .claim("userid", userId)
- .setIssuer(issuer)
- .setAudience(audience)
- .signWith(signatureAlgorithm, signingKey);
- //添加Token过期时间
- if (TTLMillis >= 0) {
- long expMillis = nowMillis + TTLMillis;
- Date exp = new Date(expMillis);
- builder.setExpiration(exp).setNotBefore(now);
- }
- //生成JWT
- return builder.compact();
- }
- }
4、添加token返回结果类AccessToken.java
- package com.xiaofangtech.sunt.jwt;
- public class AccessToken {
- private String access_token;
- private String token_type;
- private long expires_in;
- public String getAccess_token() {
- return access_token;
- }
- public void setAccess_token(String access_token) {
- this.access_token = access_token;
- }
- public String getToken_type() {
- return token_type;
- }
- public void setToken_type(String token_type) {
- this.token_type = token_type;
- }
- public long getExpires_in() {
- return expires_in;
- }
- public void setExpires_in(long expires_in) {
- this.expires_in = expires_in;
- }
- }
5、添加获取token的接口,通过传入用户认证信息(用户名、密码)进行认证获取
- package com.xiaofangtech.sunt.jwt;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.RequestBody;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
- import com.xiaofangtech.sunt.bean.UserInfo;
- import com.xiaofangtech.sunt.repository.UserInfoRepository;
- import com.xiaofangtech.sunt.utils.MyUtils;
- import com.xiaofangtech.sunt.utils.ResultMsg;
- import com.xiaofangtech.sunt.utils.ResultStatusCode;
- @RestController
- public class JsonWebToken {
- @Autowired
- private UserInfoRepository userRepositoy;
- @Autowired
- private Audience audienceEntity;
- @RequestMapping("oauth/token")
- public Object getAccessToken(@RequestBody LoginPara loginPara)
- {
- ResultMsg resultMsg;
- try
- {
- if(loginPara.getClientId() == null
- || (loginPara.getClientId().compareTo(audienceEntity.getClientId()) != 0))
- {
- resultMsg = new ResultMsg(ResultStatusCode.INVALID_CLIENTID.getErrcode(),
- ResultStatusCode.INVALID_CLIENTID.getErrmsg(), null);
- return resultMsg;
- }
- //验证码校验在后面章节添加
- //验证用户名密码
- UserInfo user = userRepositoy.findUserInfoByName(loginPara.getUserName());
- if (user == null)
- {
- resultMsg = new ResultMsg(ResultStatusCode.INVALID_PASSWORD.getErrcode(),
- ResultStatusCode.INVALID_PASSWORD.getErrmsg(), null);
- return resultMsg;
- }
- else
- {
- String md5Password = MyUtils.getMD5(loginPara.getPassword()+user.getSalt());
- if (md5Password.compareTo(user.getPassword()) != 0)
- {
- resultMsg = new ResultMsg(ResultStatusCode.INVALID_PASSWORD.getErrcode(),
- ResultStatusCode.INVALID_PASSWORD.getErrmsg(), null);
- return resultMsg;
- }
- }
- //拼装accessToken
- String accessToken = JwtHelper.createJWT(loginPara.getUserName(), String.valueOf(user.getName()),
- user.getRole(), audienceEntity.getClientId(), audienceEntity.getName(),
- audienceEntity.getExpiresSecond() * 1000, audienceEntity.getBase64Secret());
- //返回accessToken
- AccessToken accessTokenEntity = new AccessToken();
- accessTokenEntity.setAccess_token(accessToken);
- accessTokenEntity.setExpires_in(audienceEntity.getExpiresSecond());
- accessTokenEntity.setToken_type("bearer");
- resultMsg = new ResultMsg(ResultStatusCode.OK.getErrcode(),
- ResultStatusCode.OK.getErrmsg(), accessTokenEntity);
- return resultMsg;
- }
- catch(Exception ex)
- {
- resultMsg = new ResultMsg(ResultStatusCode.SYSTEM_ERR.getErrcode(),
- ResultStatusCode.SYSTEM_ERR.getErrmsg(), null);
- return resultMsg;
- }
- }
- }
6、添加使用jwt认证的filter
- package com.xiaofangtech.sunt.filter;
- import java.io.IOException;
- 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.beans.factory.annotation.Autowired;
- import org.springframework.web.context.support.SpringBeanAutowiringSupport;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.xiaofangtech.sunt.jwt.Audience;
- import com.xiaofangtech.sunt.jwt.JwtHelper;
- import com.xiaofangtech.sunt.utils.ResultMsg;
- import com.xiaofangtech.sunt.utils.ResultStatusCode;
- public class HTTPBearerAuthorizeAttribute implements Filter{
- @Autowired
- private Audience audienceEntity;
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- // TODO Auto-generated method stub
- SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
- filterConfig.getServletContext());
- }
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException {
- // TODO Auto-generated method stub
- ResultMsg resultMsg;
- HttpServletRequest httpRequest = (HttpServletRequest)request;
- String auth = httpRequest.getHeader("Authorization");
- if ((auth != null) && (auth.length() > 7))
- {
- String HeadStr = auth.substring(0, 6).toLowerCase();
- if (HeadStr.compareTo("bearer") == 0)
- {
- auth = auth.substring(7, auth.length());
- if (JwtHelper.parseJWT(auth, audienceEntity.getBase64Secret()) != null)
- {
- chain.doFilter(request, response);
- return;
- }
- }
- }
- HttpServletResponse httpResponse = (HttpServletResponse) response;
- httpResponse.setCharacterEncoding("UTF-8");
- httpResponse.setContentType("application/json; charset=utf-8");
- httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
- ObjectMapper mapper = new ObjectMapper();
- resultMsg = new ResultMsg(ResultStatusCode.INVALID_TOKEN.getErrcode(), ResultStatusCode.INVALID_TOKEN.getErrmsg(), null);
- httpResponse.getWriter().write(mapper.writeValueAsString(resultMsg));
- return;
- }
- @Override
- public void destroy() {
- // TODO Auto-generated method stub
- }
- }
7、在入口处注册filter
- package com.xiaofangtech.sunt;
- import java.util.ArrayList;
- import java.util.List;
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.boot.context.embedded.FilterRegistrationBean;
- import org.springframework.boot.context.properties.EnableConfigurationProperties;
- import org.springframework.context.annotation.Bean;
- import com.xiaofangtech.sunt.filter.HTTPBasicAuthorizeAttribute;
- import com.xiaofangtech.sunt.filter.HTTPBearerAuthorizeAttribute;
- import com.xiaofangtech.sunt.jwt.Audience;
- @SpringBootApplication
- @EnableConfigurationProperties(Audience.class)
- public class SpringRestApplication {
- public static void main(String[] args) {
- SpringApplication.run(SpringRestApplication.class, args);
- }
- @Bean
- public FilterRegistrationBean basicFilterRegistrationBean() {
- FilterRegistrationBean registrationBean = new FilterRegistrationBean();
- HTTPBasicAuthorizeAttribute httpBasicFilter = new HTTPBasicAuthorizeAttribute();
- registrationBean.setFilter(httpBasicFilter);
- List<String> urlPatterns = new ArrayList<String>();
- urlPatterns.add("/user/getuser");
- registrationBean.setUrlPatterns(urlPatterns);
- return registrationBean;
- }
- @Bean
- public FilterRegistrationBean jwtFilterRegistrationBean(){
- FilterRegistrationBean registrationBean = new FilterRegistrationBean();
- HTTPBearerAuthorizeAttribute httpBearerFilter = new HTTPBearerAuthorizeAttribute();
- registrationBean.setFilter(httpBearerFilter);
- List<String> urlPatterns = new ArrayList<String>();
- urlPatterns.add("/user/getusers");
- registrationBean.setUrlPatterns(urlPatterns);
- return registrationBean;
- }
- }
8、添加获取md5的方法类MyUtils
- package com.xiaofangtech.sunt.utils;
- import java.security.MessageDigest;
- public class MyUtils {
- public static String getMD5(String inStr) {
- MessageDigest md5 = null;
- try {
- md5 = MessageDigest.getInstance("MD5");
- } catch (Exception e) {
- e.printStackTrace();
- return "";
- }
- char[] charArray = inStr.toCharArray();
- byte[] byteArray = new byte[charArray.length];
- for (int i = 0; i < charArray.length; i++)
- byteArray[i] = (byte) charArray[i];
- byte[] md5Bytes = md5.digest(byteArray);
- StringBuffer hexValue = new StringBuffer();
- for (int i = 0; i < md5Bytes.length; i++) {
- int val = ((int) md5Bytes[i]) & 0xff;
- if (val < 16)
- hexValue.append("0");
- hexValue.append(Integer.toHexString(val));
- }
- return hexValue.toString();
- }
- }
9、在返回信息类中补充添加错误码
- INVALID_CLIENTID(30003, "Invalid clientid"),
- INVALID_PASSWORD(30004, "User name or password is incorrect"),
- INVALID_CAPTCHA(30005, "Invalid captcha or captcha overdue"),
- INVALID_TOKEN(30006, "Invalid token");
10、代码中涉及的Audience类,在上一篇文章中定义,本文不再重复说明
11、代码整体结构
12、测试
1) 获取token,传入用户认证信息
认证通过返回token信息
2) 使用上面获取的token进行接口调用
未使用token,获取token错误,或者token过期时
使用正确的token时
[转] Spring Boot实战之Filter实现使用JWT进行接口认证的更多相关文章
- 《spring boot 实战》读书笔记
前言:虽然已经用spring boot开发过一套系统,但是之前都是拿来主义,没有系统的,全面的了解过这套框架.现在通过学习<spring boot实战>这本书,希望温故知新.顺便实现自己的 ...
- spring boot实战(第一篇)第一个案例
版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] spring boot实战(第一篇)第一个案例 前言 写在前面的话 一直想将spring boot相关内容写成一个系列的 ...
- 《Spring Boot实战》笔记(目录)
目录 目 录第一部分 点睛Spring 4.x第1 章 Spring 基础 .............................................................. ...
- 《Spring Boot 实战纪实》之过滤器
导航 什么是过滤器 Spring的过滤器 Filter定义 过滤的对象 典型应用 过滤器的使用 Filter生命周期 过滤器链 自定义敏感词过滤器 新增自定义过滤器 添加 @WebFilter注解 添 ...
- spring boot实战(第十三篇)自动配置原理分析
前言 spring Boot中引入了自动配置,让开发者利用起来更加的简便.快捷,本篇讲利用RabbitMQ的自动配置为例讲分析下Spring Boot中的自动配置原理. 在上一篇末尾讲述了Spring ...
- spring boot实战(第十二篇)整合RabbitMQ
前言 最近几篇文章将围绕消息中间件RabbitMQ展开,对于RabbitMQ基本概念这里不阐述,主要讲解RabbitMQ的基本用法.Java客户端API介绍.spring Boot与RabbitMQ整 ...
- Spring Boot实战系列-----------邮件发送
快速导航 添加Maven依赖 配置文件增加邮箱相关配置 Service.Test项目代码构建 五种邮件发送类型讲解 文本邮件 html邮件 附件邮件 html内嵌图片邮件 模板邮件 问题汇总 添加ma ...
- Spring Boot 实战与原理分析视频课程
Spring Boot 实战与原理分析视频课程 链接:https://pan.baidu.com/share/init?surl=PeykcoeqZtd1d9lN9V_F-A 提取码: 关注公众号[G ...
- 9.Spring Boot实战之配置使用Logback进行日志记录
转自:https://blog.csdn.net/meiliangdeng1990/article/details/54300227 Spring Boot实战之配置使用Logback进行日志记录 在 ...
随机推荐
- 使对象可以像数组一样foreach循环,要求属性必须是私有的(写个类实现Iterator接口)
<?php class Test implements Iterator { ,,,,); public function __construct() { } // 重置,将数组内部指针指向第一 ...
- Cookie的有效访问路径
Cookie 的 作用范围: Cookie详解:https://www.cnblogs.com/handsomecui/p/6117149.html 可以作用当前目录和当前目录的子目录. 但不能作用于 ...
- BBS后台发送邮件&修改文章
一:Django发送邮件 在setting中配置 # EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST ...
- Python基础入门-元祖
其实,元组合列表的特性和使用几乎差不太多,今天我们重点来看下元组的一些操作和使用. 1.元祖的定义和特点 定义:元组是以小括号包围,元素以逗号分隔,不可变的序列之一. 特点: 1)元祖内的元素不可以增 ...
- What’s the Difference Between a Value Provider and Model Binder?
ASP.NET MVC 3 introduced the ability to bind an incoming JSON request to an action method parameter, ...
- MySQL性能调优与架构设计——第7章 MySQL数据库锁定机制
第7章 MySQL数据库锁定机制 前言: 为了保证数据的一致完整性,任何一个数据库都存在锁定机制.锁定机制的优劣直接应想到一个数据库系统的并发处理能力和性能,所以锁定机制的实现也就成为了各种数据库的核 ...
- Linq 左连接 left join
Suppose you have a tblRoom and tblUserInfo. Now, you need to select all the rooms regardless of whet ...
- 【模板】二维凸包 / [USACO5.1]圈奶牛Fencing the Cows
Problem surface 戳我 Meaning 坐标系内有若干个点,问把这些点都圈起来的最小凸包周长. 这道题就是一道凸包的模板题啊,只要求出凸包后在计算就好了,给出几个注意点 记得检查是否有吧 ...
- 十七、创建一个 WEB 服务器(一)
1.Node.js 创建的第一个应用 var http=require("http") http.createServer(function (req,res) { res.wri ...
- 【SSO单点系列】(5):CAS4.0 单点流程序列图
刚过元旦假期,感觉自己好久没写博客了,今天更新一篇,主要是CAS 的一个流程图. ps: 这两张图 是直接从官网上找的,都是简单的英语,我这种英语四级没过都看得懂,大家应该没有压力. 1.CAS 基本 ...