【jwt】使用JWT实现Token认证

为什么使用JWT?

随着技术的发展,分布式web应用的普及,通过session管理用户登录状态成本越来越高,因此慢慢发展成为token的方式做登录身份校验,然后通过token去取redis中的缓存的用户信息,随着之后jwt的出现,校验方式更加简单便捷化,无需通过redis缓存,而是直接根据token取出保存的用户信息,以及对token可用性校验,单点登录更为简单。这里还有一个在线的的JWT生成器

 

 

 什么时候你应该用JSON Web Tokens

下列场景中使用JSON Web Token是很有用的:

  • Authorization (授权) : 这是使用JWT的最常见场景。一旦用户登录,后续每个请求都将包含JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是现在广泛使用的JWT的一个特性,因为它的开销很小,并且可以轻松地跨域使用。
  • Information Exchange (信息交换) : 对于安全的在各方之间传输信息而言,JSON Web Tokens无疑是一种很好的方式。因为JWTs可以被签名,例如,用公钥/私钥对,你可以确定发送人就是它们所说的那个人。另外,由于签名是使用头和有效负载计算的,您还可以验证内容没有被篡改。

 

JSON Web Token的结构是什么样的

JSON Web Token由三部分组成,它们之间用圆点(.)连接。这三部分分别是:

  • Header
  • Payload
  • Signature

因此,一个典型的JWT看起来是这个样子的:

xxxxx.yyyyy.zzzzz

接下来,具体看一下每一部分:

Header

header典型的由两部分组成:token的类型(“JWT”)和算法名称(比如:HMAC SHA256或者RSA等等)。

例如:

然后,用Base64对这个JSON编码就得到JWT的第一部分

 

Payload

JWT的第二部分是payload,它包含声明(要求)。声明是关于实体(通常是用户)和其他数据的声明。声明有三种类型: registered, public 和 private。

  • Registered claims : 这里有一组预定义的声明,它们不是强制的,但是推荐。比如:iss (issuer), exp (expiration time), sub (subject), aud (audience)等。
  • Public claims : 可以随意定义。
  • Private claims : 用于在同意使用它们的各方之间共享信息,并且不是注册的或公开的声明。

下面是一个例子:

对payload进行Base64编码就得到JWT的第二部分

注意,不要在JWT的payload或header中放置敏感信息,除非它们是加密的。

 

Signature

为了得到签名部分,你必须有编码过的header、编码过的payload、一个秘钥,签名算法是header中指定的那个,然对它们签名即可。

例如:

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

签名是用于验证消息在传递过程中有没有被更改,并且,对于使用私钥签名的token,它还可以验证JWT的发送方是否为它所称的发送方。

 

看一张官网的图就明白了:

 

JSON Web Tokens是如何工作的

  1. 应用(或者客户端)想授权服务器请求授权。例如,如果用授权码流程的话,就是/oauth/authorize
  2. 当授权被许可以后,授权服务器返回一个access token给应用
  3. 应用使用access token访问受保护的资源(比如:API)

 

 

使用JWT核心代码:
maven依赖:

复制代码

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
     <version>3.2.0</version>
</dependency>
<dependency>
     <groupId>io.jsonwebtoken</groupId>
     <artifactId>jjwt</artifactId>
     <version>0.7.0</version>
</dependency>

复制代码

JWT工具类:

用于生成Token,和Token验证

复制代码

public class JwtUtils {
    /**
     * 签发JWT
     * 
     * @param id
     * @param subject   可以是JSON数据 尽可能少
     * @param ttlMillis
     * @return String
     *
     */
    public static String createJWT(String id, String subject, long ttlMillis) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        SecretKey secretKey = generalKey();
        JwtBuilder builder = Jwts.builder().setId(id).setSubject(subject) // 主题
                .setIssuer("user") // 签发者
                .setIssuedAt(now) // 签发时间
                .signWith(signatureAlgorithm, secretKey); // 签名算法以及密匙
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date expDate = new Date(expMillis);
            builder.setExpiration(expDate); // 过期时间
        }
        return builder.compact();
    }

    /**
     * 验证JWT
     * 
     * @param jwtStr
     * @return
     */
    public static CheckResult validateJWT(String jwtStr) {
        CheckResult checkResult = new CheckResult();
        Claims claims = null;
        try {
            claims = parseJWT(jwtStr);
            checkResult.setSuccess(true);
            checkResult.setClaims(claims);
        } catch (ExpiredJwtException e) {
            checkResult.setErrCode(SystemConstant.JWT_ERRCODE_EXPIRE);
            checkResult.setSuccess(false);
        } catch (SignatureException e) {
            checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
            checkResult.setSuccess(false);
        } catch (Exception e) {
            checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
            checkResult.setSuccess(false);
        }
        return checkResult;
    }

    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.decode(SystemConstant.JWT_SECERT);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }

    /**
     * 
     * 解析JWT字符串
     * 
     * @param jwt
     * @return
     * @throws Exception
     */
    public static Claims parseJWT(String jwt) throws Exception {
        SecretKey secretKey = generalKey();
        return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();
    }
}

复制代码

如何使用?
代码实例:

复制代码

public class LoginController {
    @Autowired
    UserRepository userRepository;
    

    @RequestMapping(value="login",method = RequestMethod.POST)
    public ReturnVo login(String username, String password,HttpServletResponse
            response) {
        User user =  userRepository.findByUsername(username);
        if(user!=null){
            if(user.getPassword().equals(password)){
                //把token返回给客户端-->客户端保存至cookie-->客户端每次请求附带cookie参数
                String JWT = JwtUtils.createJWT("1", username, SystemConstant.JWT_TTL);
                return ReturnVo.ok(JWT);
            }else{
                return ReturnVo.error();
            }
        }else{
            return ReturnVo.error();
        }
    }


    @RequestMapping(value="description",method = RequestMethod.POST)
    public ReturnVo description(String username) {
        User user =  userRepository.findByUsername(username);
        return ReturnVo.ok(user.getDescription());
    }
}

复制代码

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot中,可以使用以下步骤将JWT集成到应用程序中以实现token认证: 1. 添加依赖项 在pom.xml文件中添加以下依赖项: ``` <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> ``` 2. 创建Token工具类 创建一个JwtTokenUtil工具类,该类将用于生成和验证JWT令牌。以下是一个基本的JwtTokenUtil类: ```java public class JwtTokenUtil { private static final String SECRET_KEY = "secret"; public static String generateToken(String username) { Date now = new Date(); Date expiryDate = new Date(now.getTime() + 3600000); return Jwts.builder() .setSubject(username) .setIssuedAt(now) .setExpiration(expiryDate) .signWith(SignatureAlgorithm.HS512, SECRET_KEY) .compact(); } public static String getUsernameFromToken(String token) { return Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody() .getSubject(); } public static boolean validateToken(String token) { try { Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token); return true; } catch (SignatureException ex) { System.out.println("Invalid JWT signature"); } catch (MalformedJwtException ex) { System.out.println("Invalid JWT token"); } catch (ExpiredJwtException ex) { System.out.println("Expired JWT token"); } catch (UnsupportedJwtException ex) { System.out.println("Unsupported JWT token"); } catch (IllegalArgumentException ex) { System.out.println("JWT claims string is empty."); } return false; } } ``` 3. 创建安全配置类 创建一个SecurityConfig类,该类将用于配置Spring Security以使用JWT进行认证。以下是一个基本的SecurityConfig类: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; @Autowired private JwtUserDetailsService jwtUserDetailsService; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder()); } @Bean public JwtAuthenticationFilter jwtAuthenticationFilter() { return new JwtAuthenticationFilter(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests().antMatchers("/authenticate").permitAll() .anyRequest().authenticated().and() .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); } } ``` 4. 创建用户详细信息服务类 创建一个JwtUserDetailsService类,该类将用于从数据库或其他存储中获取用户信息以进行身份验证。以下是一个基本的JwtUserDetailsService类: ```java @Service public class JwtUserDetailsService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 在这里获取用户信息并返回UserDetails对象 return null; } } ``` 5. 创建身份验证过滤器 创建一个JwtAuthenticationFilter类,该类将用于拦截所有请求,并进行JWT身份验证。以下是一个基本的JwtAuthenticationFilter类: ```java public class JwtAuthenticationFilter 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"); } } 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)) { 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); } } ``` 6. 创建身份验证控制器 创建一个JwtAuthenticationController类,该类将用于处理身份验证请求,生成JWT令牌并返回给客户端。以下是一个基本的JwtAuthenticationController类: ```java @RestController public class JwtAuthenticationController { @Autowired private AuthenticationManager authenticationManager; @Autowired private JwtTokenUtil jwtTokenUtil; @Autowired private JwtUserDetailsService jwtUserDetailsService; @RequestMapping(value = "/authenticate", method = RequestMethod.POST) public ResponseEntity<?> createAuthenticationToken(@RequestBody JwtRequest authenticationRequest) throws Exception { authenticate(authenticationRequest.getUsername(), authenticationRequest.getPassword()); final UserDetails userDetails = jwtUserDetailsService .loadUserByUsername(authenticationRequest.getUsername()); final String token = jwtTokenUtil.generateToken(userDetails.getUsername()); return ResponseEntity.ok(new JwtResponse(token)); } 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); } } } ``` 现在,您的Spring Boot应用程序已经集成了JWT以进行身份验证。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值