[转] 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进行日志记录 在 ...
随机推荐
- 关于mysql自增字段问题
最近遇到mysql字段的自增问题,需要临时处理一下,然后就顺便补补课,这样就有了这样一篇文章. 1.自增值是什么 他是一个字段属性,是用来创建唯一标识的列的 The AUTO_INCREMENT at ...
- ROS naviagtion analysis: costmap_2d--CostmapLayer
博客转自:https://blog.csdn.net/u013158492/article/details/50493220 这个类是为ObstacleLayer StaticLayer voxelL ...
- 第七课 ROS的空间描述和变换
在命令行工具中也有一个与transformcaster相类似的工具叫做static_transform_publisher,它能够接受命令行参数来接受位置信息.旋转信息.父框架.子框架以及周期信息,通 ...
- QGIS编译教程
注意更新时间:Thursday November 02, 2017 1. Introduction 简介 This document is the original installation guid ...
- 编写高质量代码改善C#程序的157个建议——建议32:总是优先考虑泛型
建议32:总是优先考虑泛型 泛型的优点是多方面的,无论泛型类还是泛型方法都同时具备可重用性.类型安全性和高效率等特性,这是非泛型和非泛型方法无法具备的. 以可重用性为例: class MyList { ...
- [转]FreeMarker使用
copy自http://demojava.iteye.com/blog/800204 以下内容全部是网上收集: FreeMarker的模板文件并不比HTML页面复杂多少,FreeMarker模板文件主 ...
- 操作文件方法简单总结(File,Directory,StreamReader,StreamWrite ) - Zery-zhang
一 基本介绍 操作文档,文件夹,需要用到的类 1 Directory (静态类) : 用于创建.移动和删除等操作通过 目录 和子 目录 DirectoryInfo (非静态): 2 File ...
- React + Python 七月小说网 启程(一)
一.为啥要做这个网站 很久没有写技术相关的博客了,最近几个月忙飞,各种工作,技术根本学不完,很难受. 趁着春节期间,终于有空闲时间做自己爱做的事情了,美滋滋. 热爱技术,热爱小说,于是诞生了个这么玩意 ...
- 【转载】C# DataGridView 通过代码设置样式
// 表格上下左右自适应 dataGridView.Anchor = (AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom | An ...
- CentOS 6.9下PXE+Kickstart无人值守安装操作系统
一.简介 1.1 什么是PXE PXE(Pre-boot Execution Environment,预启动执行环境)是由Intel公司开发的最新技术,工作于Client/Server的网络模式,支持 ...