• Spring Boot使用JWT实现系统登录验证


    简介

    什么是JWT(Json Web Token)

    jwt是为了在网络应用环境间传递声明而执行的一种基于json的开放标准。该token被设计紧凑且安全的,特别适用于SSO场景。
    jwt的声明一般被用来在身份提供者和服务提供者之间传递被认证的用户身份信息。

    JWT长什么样

    eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0MDAyIiwiZXhwIjoxNTEwOTcwMjU4fQ._FOqy5l44hODu3DjXh762LNUTLNQH15fdCUerdseDpmSKgkVSCjOyxQNTBKDSh3N-c83_pdEw5t6BdorgRU_kw

    JWT的构成

    JWT通常由三部分组成,头信息(header)、消息体(body)、签名(signature)
    头信息指定了JWT使用的签名算法

    header={alg=HS512}

    消息体包含了JWT的意图,exp为令牌过期时间

    body={sub=testUsername, exp=1510886546}

    签名通过私钥生成

    signature=kwq8a_B6WMqHOrEi-gFR5rRPmPL7qoShZJn0VFfXpXc1Yfw6BfVrliAP9C4UnXlqD3wRXO3mw_DDIdglN5lH9Q

    使用springboot集成jwt

    jwt官网

    springboot官网

    引用依赖

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
    
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-security</artifactId>
      </dependency>
    
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-actuator</artifactId>
      </dependency>
    
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-devtools</artifactId>
      </dependency>
    
      <dependency>
          <groupId>io.jsonwebtoken</groupId>
          <artifactId>jjwt</artifactId>
          <version>0.7.0</version>
      </dependency>

    构建普通rest接口

      @RestController
      @RequestMapping("/employee")
      public class EmployeeController {
    
          @GetMapping("/greeting")
           public String greeting() {
               return "Hello,World!";
           }
       }

    JwtLoginFilter

    public class JwtLoginFilter extends UsernamePasswordAuthenticationFilter {
    
       private AuthenticationManager authenticationManager;
    
       public JwtLoginFilter(AuthenticationManager authenticationManager) {
           this.authenticationManager = authenticationManager;
       }
    
      @Override
      public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
          Employee employee = new Employee();
           return authenticationManager.authenticate(
                   new UsernamePasswordAuthenticationToken(
                       employee.getUsername(),
                       employee.getPassword(),
                       new ArrayList<>()
                  )
           );
       }
    
      @Override
      protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, 
       FilterChain chain, Authentication authResult) throws IOException, ServletException {
          String token = Jwts.builder()
               .setSubject(((User) authResult.getPrincipal()).getUsername())
               .setExpiration(new Date(System.currentTimeMillis() + 30 * 60 * 1000))
               .signWith(SignatureAlgorithm.HS512, "JWTSecret")
               .compact();
    
           response.addHeader("Authorization", JwtUtils.getTokenHeader(token));
      }

    }

    JwtAuthenticationFilter

      public class JwtAuthenticationFilter extends BasicAuthenticationFilter {
    
      public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
          super(authenticationManager);
      }
    
      @Override
      protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
          String header = request.getHeader("Authorization");
    
          if (header == null || !header.startsWith(JwtUtils.getAuthorizationHeaderPrefix())) {
              chain.doFilter(request, response);
             return;
          }
    
          UsernamePasswordAuthenticationToken authenticationToken = getUsernamePasswordAuthenticationToken(header);
    
          SecurityContextHolder.getContext().setAuthentication(authenticationToken);
          chain.doFilter(request, response);
      }
    
      private UsernamePasswordAuthenticationToken getUsernamePasswordAuthenticationToken(String token) {
          String user = Jwts.parser()
                  .setSigningKey("PrivateSecret")
                  .parseClaimsJws(token.replace(JwtUtils.getAuthorizationHeaderPrefix(), ""))
                  .getBody()
                  .getSubject();
    
          if (null != user) {
              return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
          }
    
          return null;
      }
      }

    SecurityConfiguration

      @Configuration
      @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
      public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
    
        @Override
        public void configure(WebSecurity web) throws Exception {
              super.configure(web);
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
          http.cors().and().csrf().disable().authorizeRequests()
                  .anyRequest().authenticated()
                  .and()
                  .addFilter(new JwtLoginFilter(authenticationManager()))
                  .addFilter(new JwtAuthenticationFilter(authenticationManager()));
        }
    
      }

    使用postman测试

    首先我们先测试/employee/greeting 响应如下:

    {
    "timestamp": 1510887634904,
    "status": 403,
    "error": "Forbidden",
    "message": "Access Denied",
    "path": "/employee/greeting"
    }

    很明显,状态码为403,此刻我们如果先登录拿到token后再测试呢,测试如下

    postman-test1

    登录成功后,我们可以看到headers中已经带有jwt

    authorization →Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0VXNlcm5hbWUiLCJleHAiOjE1MTA4ODkxMDd9.FtdEM0p84ff5CzDcoiQhtm1MF_NfDH2Ij1jspxlTQhuCISIzYdoU40OsFoxam9F1EXeVw2GZdQmArVwMk6HO1A

    由于postman在一般情况下不支持自定义header 这个时候我们需要下载一个插件开启interceptor 开启后将authorization 放入header继续测试:
    postman-test3

    postman-test2

    这时我们发现已经成功返回hello,world!

    最后附上代码GitHub地址:源码下载

    本文转载自

    原文作者:胡运凡

    原文链接:https://www.cnblogs.com/huyunfan/p/7850680.html

     
  • 相关阅读:
    腾讯TencentOS正式开放测试:支持“傻瓜式刷机”-android
    glob.h and glob.c for the Android NDK
    (OK) 在CentOS7—编译OpenSSL 静态库—for—Android
    Android
    Pass data to CGI script and back with jQuery.ajax
    yum—repo—How to Enable EPEL Repository for RHEL/CentOS 7/6/5
    裸机版的hello world
    CodeBlock 使用手册
    (NOT OK) How To Build CyanogenMod Android for Motorola Defy ("jordan")
    error: .repo/manifests/: contains uncommitted changes 解决办法
  • 原文地址:https://www.cnblogs.com/xifengxiaoma/p/9508477.html
Copyright © 2020-2023  润新知