Spring Boot Security And JSON Web Token 说明

流程说明

实操准备

  • 新建一个spring boot 项目,并添加hello请求

    1. 工程目录结构如下

      1. HelloWorldController 代码如下
      package com.antsdouble.demojwt.controller;
      
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RestController; @RestController
      public class HelloWorldController { @GetMapping(value = {"/hello"})
      public String hello() {
      return "Hello World JWT";
      }
      }
      1. 请求结果

  • 配置Spring Security 和JWT

    • 完整 的pom.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.2.0.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
      </parent>
      <groupId>com.antsdouble</groupId>
      <artifactId>demo-jwt</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <name>demo-jwt</name>
      <description>Demo project for Spring Boot</description>
      <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
      </properties> <dependencies>
      <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      </dependency> <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
      <exclusion>
      <groupId>org.junit.vintage</groupId>
      <artifactId>junit-vintage-engine</artifactId>
      </exclusion>
      </exclusions>
      </dependency>
      <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
      </dependency>
      <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt</artifactId>
      <version>0.9.1</version>
      </dependency>
      <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
      </dependency>
      <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      </dependency>
      </dependencies> <build>
      <plugins>
      <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
      </plugins>
      </build> </project>
    1. 生成jwt

      https://github.com/Ants-double/huanhuncao/tree/master/visio

      如果请求authenticate 则会生成jwt

    2. 检证 jwt

    ​ https://github.com/Ants-double/huanhuncao/tree/master/visio

       1. 请求业务接口带上jwt 先验证通过后再处理具体的请求

  • 配置数据库相关

    1. application.yml

       jwt:
      secret: javainuse
      spring:
      datasource:
      url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=CTT
      username: root
      password: 456123
      platform: mysql
      jpa:
      hibernate:
      ddl-auto: create-drop
    2. 添加对应的DTO 和DAO

    package com.antsdouble.demojwt.model;
    
    /**
    * @author lyy
    * @Deprecated
    * @date 2019/10/17
    */
    public class UserDTO {
    private String username;
    private String password; 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;
    }
    }
    package com.antsdouble.demojwt.dao;
    
    import com.antsdouble.demojwt.model.DAOUser;
    import org.springframework.data.repository.CrudRepository;
    import org.springframework.stereotype.Repository; /**
    * @author lyy
    * @Deprecated
    * @date 2019/10/17
    */ @Repository
    public interface UserDao extends CrudRepository<DAOUser, Integer> {
    DAOUser findByUsername(String username);
    }
    1. JwtAuthenticationController
    package com.antsdouble.demojwt.controller;
    
    import com.antsdouble.demojwt.config.JwtTokenUtil;
    import com.antsdouble.demojwt.model.JwtRequest;
    import com.antsdouble.demojwt.model.JwtResponse;
    import com.antsdouble.demojwt.model.UserDTO;
    import com.antsdouble.demojwt.service.JwtUserDetailsService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.ResponseEntity;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.authentication.BadCredentialsException;
    import org.springframework.security.authentication.DisabledException;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.web.bind.annotation.*; /**
    * @author lyy
    * @Deprecated
    * @date 2019/10/17
    */
    @RestController
    @CrossOrigin
    public class JwtAuthenticationController {
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Autowired
    private JwtUserDetailsService userDetailsService;
    @RequestMapping(value = "/authenticate", method = RequestMethod.POST)
    public ResponseEntity<?> createAuthenticationToken(@RequestBody JwtRequest authenticationRequest) throws Exception {
    authenticate(authenticationRequest.getUsername(), authenticationRequest.getPassword());
    final UserDetails userDetails = userDetailsService
    .loadUserByUsername(authenticationRequest.getUsername());
    final String token = jwtTokenUtil.generateToken(userDetails);
    return ResponseEntity.ok(new JwtResponse(token));
    }
    @RequestMapping(value = "/register", method = RequestMethod.POST)
    public ResponseEntity<?> saveUser(@RequestBody UserDTO user) throws Exception {
    return ResponseEntity.ok(userDetailsService.save(user));
    }
    private void authenticate(String username, String password) throws Exception {
    try {
    authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
    } catch (DisabledException e) {
    throw new Exception("USER_DISABLED", e);
    } catch (BadCredentialsException e) {
    throw new Exception("INVALID_CREDENTIALS", e);
    }
    }
    }
    1. WebSecurityConfig
    package com.antsdouble.demojwt.config;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.HttpMethod;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.config.http.SessionCreationPolicy;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; /**
    * @author lyy
    * @Deprecated
    * @date 2019/10/17
    */
    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
    @Autowired
    private UserDetailsService jwtUserDetailsService;
    @Autowired
    private JwtRequestFilter jwtRequestFilter;
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    // configure AuthenticationManager so that it knows from where to load
    // user for matching credentials
    // Use BCryptPasswordEncoder
    auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
    }
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
    }
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
    // We don't need CSRF for this example
    httpSecurity.csrf().disable()
    // dont authenticate this particular request
    .authorizeRequests().antMatchers("/authenticate", "/register").
    permitAll().antMatchers(HttpMethod.OPTIONS, "/**")
    .permitAll().
    // all other requests need to be authenticated
    anyRequest().authenticated().and().
    // make sure we use stateless session; session won't be used to
    // store user's state.
    exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
    .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    // Add a filter to validate the tokens with every request
    httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }
    }
    1. JwtTokenUtil
    package com.antsdouble.demojwt.config;
    
    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.stereotype.Component; import java.io.Serializable;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.function.Function; /**
    * @author lyy
    * @Deprecated
    * @date 2019/10/17
    */
    @Component
    public class JwtTokenUtil implements Serializable {
    private static final long serialVersionUID = -2550185165626007488L;
    public static final long JWT_TOKEN_VALIDITY = 5 * 60 * 60;
    @Value("${jwt.secret}")
    private String secret; //retrieve username from jwt token
    public String getUsernameFromToken(String token) {
    return getClaimFromToken(token, Claims::getSubject);
    } //retrieve expiration date from jwt token
    public Date getExpirationDateFromToken(String token) {
    return getClaimFromToken(token, Claims::getExpiration);
    } public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
    final Claims claims = getAllClaimsFromToken(token);
    return claimsResolver.apply(claims);
    } //for retrieveing any information from token we will need the secret key
    private Claims getAllClaimsFromToken(String token) {
    return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
    } //check if the token has expired
    private Boolean isTokenExpired(String token) {
    final Date expiration = getExpirationDateFromToken(token);
    return expiration.before(new Date());
    } //generate token for user
    public String generateToken(UserDetails userDetails) {
    Map<String, Object> claims = new HashMap<>();
    return doGenerateToken(claims, userDetails.getUsername());
    } //while creating the token -
    //1. Define claims of the token, like Issuer, Expiration, Subject, and the ID
    //2. Sign the JWT using the HS512 algorithm and secret key.
    //3. According to JWS Compact Serialization(https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-3.1)
    // compaction of the JWT to a URL-safe string
    private String doGenerateToken(Map<String, Object> claims, String subject) {
    return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
    .setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000))
    .signWith(SignatureAlgorithm.HS512, secret).compact();
    } //validate token
    public Boolean validateToken(String token, UserDetails userDetails) {
    final String username = getUsernameFromToken(token);
    return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }
    }
    1. JwtRequestFilter
    package com.antsdouble.demojwt.config;
    
    import com.antsdouble.demojwt.service.JwtUserDetailsService;
    import io.jsonwebtoken.ExpiredJwtException;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
    import org.springframework.stereotype.Component;
    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; /**
    * @author lyy
    * @Deprecated
    * @date 2019/10/17
    */
    @Component
    public class JwtRequestFilter extends OncePerRequestFilter {
    @Autowired
    private JwtUserDetailsService jwtUserDetailsService;
    @Autowired
    private JwtTokenUtil jwtTokenUtil; @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
    throws ServletException, IOException {
    final String requestTokenHeader = request.getHeader("Authorization");
    String username = null;
    String jwtToken = null;
    // JWT Token is in the form "Bearer token". Remove Bearer word and get
    // only the Token
    if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
    jwtToken = requestTokenHeader.substring(7);
    try {
    username = jwtTokenUtil.getUsernameFromToken(jwtToken);
    } catch (IllegalArgumentException e) {
    System.out.println("Unable to get JWT Token");
    } catch (ExpiredJwtException e) {
    System.out.println("JWT Token has expired");
    }
    catch (Exception e){
    System.out.println(e);
    }
    } else {
    logger.warn("JWT Token does not begin with Bearer String");
    }
    // Once we get the token validate it.
    if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
    UserDetails userDetails = this.jwtUserDetailsService.loadUserByUsername(username);
    // if token is valid configure Spring Security to manually set
    // authentication
    if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
    UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
    userDetails, null, userDetails.getAuthorities());
    usernamePasswordAuthenticationToken
    .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
    // After setting the Authentication in the context, we specify
    // that the current user is authenticated. So it passes the
    // Spring Security Configurations successfully.
    SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
    }
    }
    chain.doFilter(request, response);
    }
    }
    1. JwtAuthenticationEntryPoint
    package com.antsdouble.demojwt.config;
    
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.web.AuthenticationEntryPoint;
    import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.Serializable; /**
    * @author lyy
    * @Deprecated
    * @date 2019/10/17
    */
    @Component
    public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable { private static final long serialVersionUID = -7858869558953243875L;
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
    AuthenticationException authException) throws IOException {
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
    }
    }

​

​

  • 请求测试

    • localhost:8080/register

    • localhost:8080/authenticate

    • localhost:8080/hello

参考文档

https://dzone.com/articles/spring-boot-security-json-web-tokenjwt-hello-world

Spring Boot Security And JSON Web Token的更多相关文章

  1. [更新]一份包含: 采用RSA JWT(Json Web Token, RSA加密)的OAUTH2.0,HTTP BASIC,本地数据库验证,Windows域验证,单点登录的Spring Security配置文件

    没有任何注释,表怪我(¬_¬) 更新: 2016.05.29: 将AuthorizationServer和ResourceServer分开配置 2016.05.29: Token获取采用Http Ba ...

  2. Spring Boot集成JSON Web Token(JWT)

    一:认证 在了解JWT之前先来回顾一下传统session认证和基于token认证. 1.1 传统session认证 http协议是一种无状态协议,即浏览器发送请求到服务器,服务器是不知道这个请求是哪个 ...

  3. Java JWT: JSON Web Token

    Java JWT: JSON Web Token for Java and Android JJWT aims to be the easiest to use and understand libr ...

  4. Spring Boot Security 整合 JWT 实现 无状态的分布式API接口

    简介 JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案.JSON Web Token 入门教程 - 阮一峰,这篇文章可以帮你了解JWT的概念.本文重点讲解Spring Boo ...

  5. Spring Boot Security JWT 整合实现前后端分离认证示例

    前面两章节我们介绍了 Spring Boot Security 快速入门 和 Spring Boot JWT 快速入门,本章节使用 JWT 和 Spring Boot Security 构件一个前后端 ...

  6. 如何在SpringBoot中集成JWT(JSON Web Token)鉴权

    这篇博客主要是简单介绍了一下什么是JWT,以及如何在Spring Boot项目中使用JWT(JSON Web Token). 1.关于JWT 1.1 什么是JWT 老生常谈的开头,我们要用这样一种工具 ...

  7. JSON Web Token – 在 Web 应用间安全地传递信息

    出处:子回 使用 JWT 令牌和 Spring Security 来实现身份验证 八幅漫画理解使用JSON Web Token设计单点登录系统

  8. JWT—JSON Web Token - 理解JWT网络间应用用户安全认证交互设计

    原文地址:http://blog.leapoahead.com/2015/09/06/understanding-jwt/ 官网地址:https://jwt.io/ JSON Web Token(JW ...

  9. 你知道你对 JSON Web Token 的认识存在误解吗

    1.前言 JSON Web Token (JWT) 其实目前已经广为软件开发者所熟知了,但是 JOSE (Javascript Object Signing and Encryption) 却鲜有人知 ...

随机推荐

  1. vim编辑python脚本时Tab补全

    所属分类:成长之路 使用Linux写python脚本的时候,初期最痛苦的是什么?当然是各种库的不熟悉,知道了库,里面的方法还要挨个看,挨个记. 所以这时候,很多小伙伴使用了ipython,最强大的功能 ...

  2. Android Studio [WebView]

    WebViewActivity.java package com.xdw.a122; import android.graphics.Bitmap; import android.support.v7 ...

  3. Knative 实战:基于 Knative Serverless 技术实现天气服务-上篇

    提到天气预报服务,我们第一反应是很简单的一个服务啊,目前网上有大把的天气预报 API 可以直接使用,有必要去使用 Knative 搞一套吗?杀鸡用牛刀?先不要着急,我们先看一下实际的几个场景需求: 场 ...

  4. redis分布式锁-WATCH锁(废弃)

    使用watch构建锁的代码结构.(最着负载不断增加,系统完成一次加锁操作,重试次数不断加大) pine=conn.pineline while pine.watch if xxx pine.unwat ...

  5. Linux环境下实现对文件读写操作

    ---- 今天分享一下在linux系统在实现对文件读写一些基本的操作,在这之前我们要掌握一些基本的技能在Linux环境下.比如查看命令和一个函数的具体用法,就是相当于查手册,在Linux下有一个man ...

  6. java8 Optional使用总结

    [前言] java8新特性 java8 函数接口 java8 lambda表达式 Java 8 时间日期使用 java8 推出的Optional的目的就是为了杜绝空指针异常,帮助开发者开发出更优雅的代 ...

  7. 【爬虫小程序:爬取斗鱼所有房间信息】Xpath(多进程版)

    # 本程序亲测有效,用于理解爬虫相关的基础知识,不足之处希望大家批评指正 import requests from lxml import etree from multiprocessing imp ...

  8. RBD 基本使用 - Storage6

    块存储管理系列文章 (1)RBD 基本使用 - Storage6 (2)iSCSI 网关管理 (3)使用 librbd 将虚拟机运行在 Ceph RBD (4)RBD Mirror 容灾 Ceph 块 ...

  9. vue 引入 fontawesome 报错 Could not find one or more icon(s) 解决

    在 vue 项目中引用 fontawesome , 按照官方说明如下步骤操作 1. 终端中执行 $ npm i --save @fortawesome/fontawesome-svg-core $ n ...

  10. Django之使用redis缓存session,历史浏览记录,首页数据实现性能优化

    Redis缓存session 配置Django缓存数据到redis中 # diango的缓存配置 CACHES = { "default": { "BACKEND&quo ...