Token 认证登录

Token

        转:什么是Token(令牌)-菜鸟笔记

        关于Token 登录:Token登录认证

简单介绍

  • 访问资源接口(API)时所需要的资源凭证

  • 简单token 的组成: uid(用户唯一的身份标识) 、time (当前时间的时间戳) ,sign(签名,token的前几位以hash算法压缩成的一定长度的16进制字符串)

  • 特点

    • 服务端无状态变化、可扩展性好

    • 支持移动端设备

    • 安全

    • 支持跨域程序调用

    • token 的身份验证流程

      •  1、客户端使用用户名和密码进行登录
      • 2、服务端收到请求,去验证用户名与密码
      • 3、验证成功后,服务端会签发一个token 并把这个token 发送给客户端
      • 4、客户端收到token后,会把它存储起来,比如放在cookie 里 或者 localStorage里
      • 5、客户端每次向服务端请求资源的时候需要带着服务端签发的token
      • 6、服务端收到请求后,先验证客户端请求里带着的token ,如果验证成功,就向客户端返回请求的数据 
      • 优点:
        • 每一次请求都需要携带token ,需要把token 放到HTTP的Header 里
        • 基于token 的用户验证是一种服务端无状态的认证方式,服务端不用存放token数据,用解析token的计算时间换取 session的存储空间,从而减轻服务器的压力,减少频繁的查询数据库
        • token 完全由应用管理,所以它可以避开同源策略
      • Token生成示例
        使用用户唯一ID + 系统时间 + 随机数 + 过期时间得到用户信息数据,对用户信息数据进行RSA非对称加密/AES对称加密得到一个加密字符串A,将加密字符串A再次进行签名等到一个签名数据。然后将签名数据和加密字符串进行拼接,最后使用base64进行编码,得到最终的token令牌。
      	/**
       *
       * @param tokenBody 实例对象,通常为bean
       * @param minute 过期时间   单位:min
       * @param <T>
       * @return
       */
      public static <T> String createToken(T tokenBody, int minute) {
            
          long now = System.currentTimeMillis() / 1000;
          Gson gson = new Gson();
          JsonObject jsonBody = new JsonObject();
          jsonBody.addProperty("body", gson.toJson(tokenBody));
      
          String randomAlphabetic = RandomStringUtils.randomAlphabetic(3);
          JsonObject jsonHeader = new JsonObject();
          jsonHeader.addProperty("now", now);
          jsonHeader.addProperty("rand_num", randomAlphabetic);
          jsonHeader.addProperty("expire", (now + minute * 60));
      
          String token = null;
          try {
            
              byte[] encryptContent = generateEncryptBody(jsonHeader.toString(), jsonHeader.toString());
              byte[] signWithEncrypt = generateSignWithEncrypt(encryptContent);
              token = Joiner.on(".").join(new String[]{
            base64Encoder(
                      jsonHeader.toString().getBytes("utf-8")),
                      base64Encoder(encryptContent),
                      base64Encoder(signWithEncrypt)}
                      );
          } catch (Exception e) {
            
              e.printStackTrace();
          }
          return token;
      }

    常见的鉴权模式

    • session-Cookie
    • Token验证(JWT SSO单点登录)
    • OAuth2.0 (开放授权)
  • JWT 与 Token 的区别

    • 相同:
      • 都是访问资源的令牌
      • 都可以记录用户的信息
      • 都是使服务端无状态变化
      • 都是验证成功后,客户端才能访问服务端上受保护的资源
  • 区别

    • Token: 服务端验证客户端发送过来的Token 时,还需要查询数据库获取用户信息,然后验证Token 是否有效
    • JWT: 将token 和 Payload 加密后存储于客户端,服务端只需要使用秘钥进行校验即可,不需要查询或者减少查询数据库,因为JWT自包含了用户信息和加密的数据
  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用Spring Security来实现Token认证。以下是一个简单的示例: 1. 添加依赖 在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ``` 2. 配置Spring Security 在Spring Boot的配置类中,添加以下配置: ```java @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private MyUserDetailsService userDetailsService; @Autowired private JwtRequestFilter jwtRequestFilter; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests().antMatchers("/authenticate").permitAll(). anyRequest().authenticated().and(). exceptionHandling().and().sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources/**", "/configuration/security", "/swagger-ui.html", "/webjars/**", "/api-docs/**"); } } ``` 其中,`MyUserDetailsService`是一个自定义的`UserDetailsService`实现,用于获取用户信息;`JwtRequestFilter`是一个自定义的过滤器,用于解析和验证Token。 3. 实现认证接口 创建一个`AuthenticationController`类,实现登录认证接口: ```java @RestController public class AuthenticationController { @Autowired private AuthenticationManager authenticationManager; @Autowired private JwtTokenUtil jwtTokenUtil; @Autowired private MyUserDetailsService userDetailsService; @PostMapping("/authenticate") public ResponseEntity<?> createAuthenticationToken(@RequestBody AuthenticationRequest authenticationRequest) throws Exception { try { authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword())); } catch (BadCredentialsException e) { throw new Exception("Incorrect username or password", e); } final UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationRequest.getUsername()); final String token = jwtTokenUtil.generateToken(userDetails); return ResponseEntity.ok(new AuthenticationResponse(token)); } } ``` 其中,`AuthenticationRequest`是一个包含用户名和密码的DTO对象;`AuthenticationResponse`是一个包含Token的DTO对象。 4. 实现自定义UserDetailsService 创建一个`MyUserDetailsService`类,实现`UserDetailsService`接口,用于获取用户信息。这里假设用户信息存储在数据库中。 ```java @Service public class MyUserDetailsService implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username); if (user == null) { throw new UsernameNotFoundException("User not found with username: " + username); } return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), new ArrayList<>()); } } ``` 5. 实现自定义JwtTokenUtil 创建一个`JwtTokenUtil`类,用于生成和解析Token。这里使用了`io.jsonwebtoken`库来实现。 ```java @Component public class JwtTokenUtil { private static final String SECRET_KEY = "secret"; public String generateToken(UserDetails userDetails) { Map<String, Object> claims = new HashMap<>(); return createToken(claims, userDetails.getUsername()); } private String createToken(Map<String, Object> claims, String subject) { long now = System.currentTimeMillis(); long validity = now + 3600000; return Jwts.builder() .setClaims(claims) .setSubject(subject) .setIssuedAt(new Date(now)) .setExpiration(new Date(validity)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); } public boolean validateToken(String token, UserDetails userDetails) { final String username = getUsernameFromToken(token); return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); } private boolean isTokenExpired(String token) { final Date expiration = getExpirationDateFromToken(token); return expiration.before(new Date()); } private Date getExpirationDateFromToken(String token) { return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getExpiration(); } public String getUsernameFromToken(String token) { return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getSubject(); } } ``` 其中,`SECRET_KEY`是用于签名的密钥。 6. 实现自定义JwtRequestFilter 创建一个`JwtRequestFilter`类,继承`OncePerRequestFilter`,用于解析和验证Token。 ```java @Component public class JwtRequestFilter extends OncePerRequestFilter { @Autowired private JwtTokenUtil jwtTokenUtil; @Autowired private MyUserDetailsService userDetailsService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { final String authorizationHeader = request.getHeader("Authorization"); String username = null; String jwt = null; if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { jwt = authorizationHeader.substring(7); username = jwtTokenUtil.getUsernameFromToken(jwt); } if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); if (jwtTokenUtil.validateToken(jwt, userDetails)) { UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); usernamePasswordAuthenticationToken .setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); } } chain.doFilter(request, response); } } ``` 7. 测试接口 使用Postman等工具,向`/authenticate`接口发送POST请求,请求体中包含用户名和密码,如: ```json { "username": "test", "password": "test" } ``` 如果用户名和密码正确,接口将返回一个包含Token的JSON对象,如: ```json { "token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0IiwiaWF0IjoxNTYwMzQwNTQ3LCJleHAiOjE1NjAzNDQxNDd9.1x4abT-7TbBw4S7n5fFwKkqYQ8mlmW84v6vKjL_6iQI" } ``` 之后,每次请求需要认证的接口时,需要在请求头中添加`Authorization`字段,值为`Bearer <Token>`,如: ``` Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0IiwiaWF0IjoxNTYwMzQwNTQ3LCJleHAiOjE1NjAzNDQxNDd9.1x4abT-7TbBw4S7n5fFwKkqYQ8mlmW84v6vKjL_6iQI ``` 如果Token有效,接口将返回相应的数据。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值