扫码关注带你吊爆Java后端技术
哈喽,各位新来的小伙伴们,大家好!由于公众号做了改版,为了保证公众号的资源能准时推送到你手里,大家记得将后端君的公众号 加星标置顶 ,在此真诚的表示感谢~
来源:blog.csdn.net/change_on/article/details/76279441
上一篇:Spring Boot + GraphQL 才是 API 的未来!
正文
JWTs是JSON对象的编码表示。JSON对象由零或多个名称/值对组成,其中名称为字符串,值为任意JSON值。
JWT有助于在clear(例如在URL中)发送这样的信息,可以被信任为不可读(即加密的)、不可修改的(即签名)和URL - safe(即Base64编码的)。
例如:
Header:{ "alg": "HS256", "typ": "JWT"}Claims:{ "sub": "1234567890", "name": "John Doe", "admin": true}Signature:base64UrlEncode(Header) + "." + base64UrlEncode(Claims),
加密生成的token:
有很多库可以帮助您创建和验证JWT,但是当使用JWT时,仍然可以做一些事情来限制您的安全风险。在您信任JWT中的任何信息之前,请始终验证签名。这应该是给定的。
换句话说,如果您正在传递一个秘密签名密钥到验证签名的方法,并且签名算法被设置为“none”,那么它应该失败验证。
确保签名的秘密签名,用于计算和验证签名。秘密签名密钥只能由发行者和消费者访问,不能在这两方之外访问。
不要在JWT中包含任何敏感数据。这些令牌通常是用来防止操作(未加密)的,因此索赔中的数据可以很容易地解码和读取。
如果您担心重播攻击,包括一个nonce(jti索赔)、过期时间(exp索赔)和创建时间(iat索赔)。这些在JWT规范中定义得很好。
JJWT是一个提供端到端的JWT创建和验证的Java库。永远免费和开源(Apache License,版本2.0),JJWT很容易使用和理解。它被设计成一个以建筑为中心的流畅界面,隐藏了它的大部分复杂性。
这里以github上的demo演示,理解原理,集成到自己项目中即可。
结构图
Maven 引进 : pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.nibado.example</groupId> <artifactId>jwt-angular-spring</artifactId> <version>0.0.2-SNAPSHOT</version> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <commons.io.version>2.4</commons.io.version> <jjwt.version>0.6.0</jjwt.version> <junit.version>4.12</junit.version> <spring.boot.version>1.5.3.RELEASE</spring.boot.version> </properties> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring.boot.version}</version> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>${spring.boot.version}</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>${commons.io.version}</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>${jjwt.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> </dependencies></project>
WebApplication.java
搜索公众号Java后端栈后台回复“面试”,获取一份惊喜礼包。
package com.nibado.example.jwtangspr;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;import org.springframework.boot.web.servlet.FilterRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;@EnableAutoConfiguration@ComponentScan@Configurationpublic class WebApplication { //过滤器 @Bean public FilterRegistrationBean jwtFilter() { final FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(new JwtFilter()); registrationBean.addUrlPatterns("/api/*"); return registrationBean; } public static void main(final String[] args) throws Exception { SpringApplication.run(WebApplication.class, args); }}
JwtFilter.java
package com.nibado.example.jwtangspr;import java.io.IOException;import javax.servlet.FilterChain;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import org.springframework.web.filter.GenericFilterBean;import io.jsonwebtoken.Claims;import io.jsonwebtoken.Jwts;import io.jsonwebtoken.SignatureException;public class JwtFilter extends GenericFilterBean { @Override public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain) throws IOException, ServletException { final HttpServletRequest request = (HttpServletRequest) req; //客户端将token封装在请求头中,格式为(Bearer后加空格):Authorization:Bearer +token final String authHeader = request.getHeader("Authorization"); if (authHeader == null || !authHeader.startsWith("Bearer ")) { throw new ServletException("Missing or invalid Authorization header."); } //去除Bearer 后部分 final String token = authHeader.substring(7); try { //解密token,拿到里面的对象claims final Claims claims = Jwts.parser().setSigningKey("secretkey") .parseClaimsJws(token).getBody(); //将对象传递给下一个请求 request.setAttribute("claims", claims); } catch (final SignatureException e) { throw new ServletException("Invalid token."); } chain.doFilter(req, res); }}
UserController.java
package com.nibado.example.jwtangspr;import java.util.Arrays;import java.util.Date;import java.util.HashMap;import java.util.List;import java.util.Map;import javax.servlet.ServletException;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RestController;import io.jsonwebtoken.Jwts;import io.jsonwebtoken.SignatureAlgorithm;@RestController@RequestMapping("/user")public class UserController { //这里模拟数据库 private final Map<String, List<String>> userDb = new HashMap<>(); @SuppressWarnings("unused") private static class UserLogin { public String name; public String password; } public UserController() { userDb.put("tom", Arrays.asList("user")); userDb.put("wen", Arrays.asList("user", "admin")); } /*以上是模拟数据库,并往数据库插入tom和sally两条记录*/ @RequestMapping(value = "login", method = RequestMethod.POST) public LoginResponse login(@RequestBody final UserLogin login) throws ServletException { if (login.name == null || !userDb.containsKey(login.name)) { throw new ServletException("Invalid login"); } //加密生成token return new LoginResponse(Jwts.builder().setSubject(login.name) .claim("roles", userDb.get(login.name)).setIssuedAt(new Date()) .signWith(SignatureAlgorithm.HS256, "secretkey").compact()); } @SuppressWarnings("unused") private static class LoginResponse { public String token; public LoginResponse(final String token) { this.token = token; } }}
ApiController.java
package com.nibado.example.jwtangspr;import io.jsonwebtoken.Claims;import java.util.List;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/api")public class ApiController { @SuppressWarnings("unchecked") @RequestMapping(value = "role/{role}", method = RequestMethod.GET) public Boolean login(@PathVariable final String role, final HttpServletRequest request) throws ServletException { final Claims claims = (Claims) request.getAttribute("claims"); return ((List<String>) claims.get("roles")).contains(role); }}
index.html
<!doctype html><html ng-app="myApp"><head> <meta charset="utf-8"/> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/> <title>JSON Web Token / AngularJS / Spring Boot example</title> <meta name="description" content=""> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="libs/bootstrap/css/bootstrap.css"> <script src="libs/jquery/jquery.js"></script> <script src="libs/bootstrap/js/bootstrap.js"></script> <script src="libs/angular/angular.js"></script> <script src="app.js"></script></head><body><div class="container" ng-controller='MainCtrl'> <h1>{{greeting}}</h1> <div ng-show="!loggedIn()"> Please log in (tom and sally are valid names)</br> <form ng-submit="login()"> Username: <input type="text" ng-model="userName"/><span><input type="submit" value="Login"/> </form> </div> <div class="alert alert-danger" role="alert" ng-show="error.data.message"> <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <span class="sr-only">Error:</span> {{error.data.message}} </div> <div ng-show="loggedIn()"> <div class="row"> <div class="col-md-6"> <h3><span class="label label-success">Success!</span> Welcome {{userName}}</h3> <a href ng-click="logout()">(logout)</a> </div> <div class="col-md-4"> <div class="row header"> <div class="col-sm-4">{{userName}} is a</div> </div> <div class="row"> <div class="col-sm-2">User</div> <div class="col-sm-2"><span class="glyphicon glyphicon-ok" aria-hidden="true" ng-show="roleUser"></span></div> </div> <div class="row"> <div class="col-sm-2">Admin</div> <div class="col-sm-2"><span class="glyphicon glyphicon-ok" aria-hidden="true" ng-show="roleAdmin"></span></div> </div> <div class="row"> <div class="col-sm-2">Foo</div> <div class="col-sm-2"><span class="glyphicon glyphicon-ok" aria-hidden="true" ng-show="roleFoo"></span></div> </div> </div> </div> </div></div></body></html>
app.js
搜索公众号顶级算法后台回复“算法心得”,获取一份惊喜礼包。
var appModule = angular.module('myApp', []);appModule.controller('MainCtrl', ['mainService','$scope','$http', function(mainService, $scope, $http) { $scope.greeting = 'Welcome to the JSON Web Token / AngularJR / Spring example!'; $scope.token = null; $scope.error = null; $scope.roleUser = false; $scope.roleAdmin = false; $scope.roleFoo = false; $scope.login = function() { $scope.error = null; mainService.login($scope.userName).then(function(token) { $scope.token = token; $http.defaults.headers.common.Authorization = 'Bearer ' + token; $scope.checkRoles(); }, function(error){ $scope.error = error $scope.userName = ''; }); } $scope.checkRoles = function() { mainService.hasRole('user').then(function(user) {$scope.roleUser = user}); mainService.hasRole('admin').then(function(admin) {$scope.roleAdmin = admin}); mainService.hasRole('foo').then(function(foo) {$scope.roleFoo = foo}); } $scope.logout = function() { $scope.userName = ''; $scope.token = null; $http.defaults.headers.common.Authorization = ''; } $scope.loggedIn = function() { return $scope.token !== null; } } ]);appModule.service('mainService', function($http) { return { login : function(username) { return $http.post('/user/login', {name: username}).then(function(response) { return response.data.token; }); }, hasRole : function(role) { return $http.get('/api/role/' + role).then(function(response){ console.log(response); return response.data; }); } };});
运行应用
效果
◆ ◆ ◆ ◆ ◆
为什么阿里强制 boolean 类型变量不能使用 is 开头?
死磕18个Java8日期处理,工作必用!收藏起来~
12306抢票:极限并发带来的思考
Java 这个高级特性,很多人还没用过!
史上最全的Excel导入导出,这也太香了吧!!!
欢迎添加栈哥个人微信 ysle007 进粉丝群或围观朋友圈
文章有问题?点此查看未经处理的缓存