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. 树莓派3安装openwrt

    1.在编译openwrt之前,需要先安装依赖包,命令如下: sudo apt-get install autoconf binutils bison bzip2 flex gawk gettext m ...

  2. .Net Core WebApi(二)在Windows服务器上部署

    上一篇学习到了如何简单的创建.Net Core Api和Swagger使用,既然写了接口,那么就需要部署到服务器上才能够正式使用.服务器主要用到了两种系统,Windows和Linux,.Net和Win ...

  3. 首次GitHub千星项目提交维护成功 留念

    现在有点激动,可能有混乱的地方.请大家见谅. 一直觉得千星项目,对我来说是一个遥不可及的地方.没想到第一次在GitHub上 提交Pull Request 就成功了,并且是一个千星项目. 虽然 只是提出 ...

  4. C++ 函数模板用法

    泛型编程概念:不考虑具体数据类型的编程方式: 函数模板: 1.提供一种特殊的函数可用不同类型进行调用: 2.与普通函数很相似,区别是类型可被参数化: template <typename T&g ...

  5. 夯实Java基础系列10:深入理解Java中的异常体系

    目录 为什么要使用异常 异常基本定义 异常体系 初识异常 异常和错误 异常的处理方式 "不负责任"的throws 纠结的finally throw : JRE也使用的关键字 异常调 ...

  6. Android系统开发实务实训

    实训项目 :               Android系统开发实务实训                           项目成品名称:         绝地坦克                 ...

  7. 深入Dapper.NET源码 (文长)

    目录 前言.目录.安装环境 Dynamic Query 原理 Part1 Dynamic Query 原理 Part2 Strongly Typed Mapping 原理 Part1 : ADO.NE ...

  8. 创建一个自己的Vue UI组件库,并将它发布在npm上

    本文仅限于入门级,没有成规模制作,希望能对你有所帮助. 因为在开发多个项目中可能会用到同一个组件,那么我们通过复制粘贴的形式更新,无异于是笨拙的,我们可以通过上传到npm后,不断迭代npm包来实现更新 ...

  9. 【主动学习】Variational Adversarial Active Learning

    本文记录了博主阅读ICCV2019一篇关于主动学习论文的笔记,第一篇博客,以后持续更新哈哈 论文题目:<Variational AdVersarial Active Learning> 原 ...

  10. asp.net core 使用 AccessControlHelper 控制访问权限

    asp.net core 使用 AccessControlHelper 控制访问权限 Intro 由于项目需要,需要在基于 asp.net mvc 的 Web 项目框架中做权限的控制,于是才有了这个权 ...