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. 将字符串转换成json格式

    1.引入json依赖,在pom.xml文件里添加如下内容 <!--Json array start --> <dependency> <groupId>common ...

  2. 微信小程序开发简述

    微信小程序简述 什么是微信小程序? 微信小程序,简称小程序,英文名Mini Program,是一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或搜一下即可打开应用.全面开放 ...

  3. 一个js破解教程

    很好的一篇文章,先存着以后用到. 为了防止官网更新修复,存一下版本 https://pan.lanzou.com/b220073/ 密码:这是秘密 这篇文章以 JavaScript 为例讲解了破解的一 ...

  4. 手把手教你搭建Pytest+Allure2.X环境详细教程,生成让你一见钟情的测试报告(非常详细,非常实用)

    简介 宏哥之前在做接口自动化的时候,用的测试报告是HTMLTestRunner,虽说自定义模板后能满足基本诉求,但是仍显得不够档次,高端,大气,遂想用其他优秀的report框架替换之.一次偶然的机会, ...

  5. java @postconstruct初始化注解使用

    1.从Java EE 5规范开始,Servlet中增加了两个影响Servlet生命周期的注解(Annotion):@PostConstruct和@PreDestroy.这两个注解被用来修饰一个非静态的 ...

  6. .Net Core Serverless初体验

    什么是Serverless Serverless 是一个当今软件世界中比较新的话题.它并没有一个普遍公认的权威定义,每个人每个企业对它的解释可能都有不同,而 Serverless 正是在这种情况下不断 ...

  7. JVM Java字节码的角度分析switch的实现

    目录 Java字节码的角度分析switch的实现 引子 前置知识 一个妥协而又枯燥的方案 switch的实现 回顾历史 字节码分析 其他实现方式? Java字节码的角度分析switch的实现 作者 k ...

  8. 详述Python序列化

    一.前言 1. 现实需求 每种编程语言都有各自的数据类型,其中面向对象的编程语言还允许开发者自定义数据类型(如:自定义类),Python也是一样.很多时候我们会有这样的需求: 把内存中的各种数据类型的 ...

  9. vue-cli脚手架项目本地阅览和在线阅览

    一.需求 开发环境:当然啦,前提是你要完整检测整个项目无错误的运行:npm run dev 后项目在本地预览问题没有问题 二.服务器本地阅览 生产环境:项目制作完成后需执行npm run build操 ...

  10. lnmp环境搭设

    安装nginx============================ 1添加nginx的rpm信息 rpm -Uvh http://nginx.org/packages/centos/7/noarc ...