Java实现基于token认证的方法示例

我来为您讲解“Java实现基于token认证的方法示例”的完整攻略。

什么是token认证

Token认证是现在比较流行的Web应用程序认证方法之一。它能解决基于session认证的一些问题,比如跨站点请求伪造(CSRF)和分布式系统中的会话共享的问题。用户只需要通过用户名和密码一次验证,在服务器成功认证后,服务器会返回一个token给客户端。客户端在后续的访问请求中带上这个token来进行身份验证,避免了使用 cookie 造成的一些基于 session 认证的安全问题。

实现基于token认证的方法

要实现基于token认证的方法具体分为以下步骤:

  1. 用户登录时,客户端向服务器发送用户名和密码。
  2. 服务器验证用户名和密码是否正确,如果正确则在服务器端生成一个token,并保存该 token 到数据库中。同时返回给客户端该token作为登录凭证。
  3. 客户端将这个 token 存储在本地存储器中,例如localStorage。
  4. 在每次向服务器发送请求时,客户端将token添加到请求的头部中,例如Authorization头部。
  5. 服务器通过获取请求头部中的 Authorization 字段获取该请求的token,然后从数据库中查询该 token 是否存在。如果存在,则说明该请求的用户已经通过了身份认证,服务器为请求提供相应的服务。

下面给出一个Java实现基于token认证的示例,帮助大家更好的理解token认证的流程。

示例一

这个示例使用Spring框架实现基于token认证的方法。

首先,我们需要在Spring Security中配置Token-Based Authentication:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private JwtAuthenticationEntryPoint unauthorizedHandler;

    @Autowired
    pivate JwtTokenUtil jwtTokenUtil;

    @Bean
    public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
        return new JwtAuthenticationTokenFilter();
    }

    @Override
    protected voird configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable()
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .antMatchers("/auth/**").permitAll()
                .anyRequest().authenticated();

        // 添加一个过滤器以验证token
        httpSecurity.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);

        // 禁用缓存
        httpSecurity.headers().cacheControl();
    }

    @Override
    public void configure(WebSecurity webSecurity) throws Exception {
        // 允许 Swagger2 访问
        webSecurity.ignoring().antMatchers("/v2/api-docs", "/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/images/**");
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

在上述代码中,我们从用户获取其username和password来认证,如果成功,将生成并返回一个JWT token。此时,token已经保存在客户端中,可以在以后的请求中使用。

接下来,我们需要实现一个类来提供token的生成和验证功能。下面是一个示例:

@Service
public class JwtTokenService {

    @Value("${jwt.secret}")
    private String secret;

    // 定义过期时间为1小时
    private static final long EXPIRATION_TIME = 60 * 60 * 1000;

    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("sub", userDetails.getUsername());
        claims.put("iat", new Date(System.currentTimeMillis()));
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    public boolean validateToken(String token, UserDetails userDetails) {
        final String username = getUsernameFromToken(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }

    public String getUsernameFromToken(String token) {
        return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody().getSubject();
    }

    private Date getExpirationDateFromToken(String token) {
        return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody().getExpiration();
    }

    private boolean isTokenExpired(String token) {
        final Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }
}

在上面的代码中,我们定义了如下方法:

  • generateToken:生成token;
  • validateToken:验证token是否有效;
  • getUsernameFromToken:获取token中的用户名;
  • getExpirationDateFromToken:获取token的过期时间;
  • isTokenExpired:判断token是否过期。

我们还可以验证前端传过来的 token 是否合法,下面是一个示例:

@Service
public class JwtUserDetailsService implements UserDetailsService {

    @Autowired
    private JwtTokenService jwtTokenService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 假设这里是从数据库中查询用户信息
        return new User(username, "", new ArrayList<>());
    }

    public boolean validateToken(String token) {
        String username = jwtTokenService.getUsernameFromToken(token);
        UserDetails userDetails = this.loadUserByUsername(username);
        return jwtTokenService.validateToken(token, userDetails);
    }
}

在上述代码中,当从前端接收到一个token时,在这个方法中调用jwtTokenService的validateToken方法验证该token是否合法。

示例二

下面是一个更简单的示例,使用JAX-RS框架和Jersey实现基于token认证的方法。在 Jersey 中使用 HTTP 请求处理函数(@POST, @GET, @PUT, @DELETE) 和 Resouce 模块(@Path、@Produces、@Consumes)定义一个 API。此示例使用的是 JJWT(JSON Web Token for Java) 以及基本的 web servlet,其余的代码都是 java。

@Path("/your/resource")
public class YourResource {

    @POST
    @Path("/login")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response login(User user) {
        // ...
        String jwt = createJWT(user);
        return Response.ok().entity(jwt).build();
    }

    @GET
    @Path("/secured")
    @Produces(MediaType.APPLICATION_JSON)
    public Response secureEndpoint(@HeaderParam("Authorization") String authHeader) throws JsonProcessingException {
        // 验证 token 是否正确
        JwtToken jwtToken = JwtTokenService.verifyToken(authHeader);
        if (jwtToken != null && jwtToken.getPayload().get("sub") != null) {
            // 用户重载并返回受保护的数据
            User user = retrieveUserFromDatabase(jwtToken.getPayload().get("sub").toString());
            return Response.ok().entity(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(user)).build();
        }
        return Response.status(Response.Status.UNAUTHORIZED).build();
    }

    @SuppressWarnings("deprecation")
    private String createJWT(User user) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, 7);
        JwtBuilder builder = Jwts.builder()
                .setPayload(new Gson().toJson(user))
                .setExpiration(calendar.getTime())
                .signWith(SignatureAlgorithm.HS512, "mySecretKey");
        return builder.compact();
    }

    private User retrieveUserFromDatabase(String username) {
        // ...
        return new User();
    }
}

在上述代码中,我们定义了一个包含两个方法的类YourResource,其中:

  1. login() 方法是一个带有@POST注解的方法,用于从客户端获取用户凭证。在这个方法里,我们生成JWT并返回给客户端,客户端将此token保存在本地存储器中。
  2. secureEndpoint() 方法是一个带有@GET注解的方法,在前端发来的请求中验证此请求的 token 是否有效,如果有效,返回受保护的文本数据。在这个方法中,我们调用JwtTokenServiceverifyToken方法来验证token是否有效。

至此,我们就学习到了Java实现基于token认证的方法。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java实现基于token认证的方法示例 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • java复制文件和java移动文件的示例分享

    下面是Java复制文件和移动文件的示例攻略: 复制文件 1. 使用Java NIO库 Java NIO库提供了Channel和ByteBuffer两个类来进行文件复制操作。以下是一个简单的示例: import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.B…

    Java 2023年5月20日
    00
  • Java BigDecimal基础用法详解

    Java BigDecimal基础用法详解 什么是BigDecimal Java中的float和double类型是不能精确表示十进制数的,这对于很多需要精确计算的场景是不适用的。而BigDecimal是Java提供的一个可以精确表示任意大小和精度的十进制数类。 常用构造方法 BigDecimal(double val):通过一个Double类型的值来构造Bi…

    Java 2023年5月26日
    00
  • 简洁实用的Java Base64编码加密异常处理类代码

    我们来讲解一下“简洁实用的Java Base64编码加密异常处理类代码”的完整攻略。 什么是Base64编码加密? Base64编码是一种将二进制数据转换成文本数据的方法,它可以用来将数据在网络上进行传输。Base64编码是一种简单、可逆的编码方式,目前广泛应用于各种网络协议和文件格式。在Java中可以使用Base64编码对二进制数据进行加密。 Java中的…

    Java 2023年5月20日
    00
  • 关于Java实现HttpServer模拟前端接口调用

    关于Java实现HttpServer模拟前端接口调用,可以按照以下步骤进行: 一、实现HttpServer 1.引入HttpServer依赖,例如使用Jetty <dependencies> <dependency> <groupId>org.eclipse.jetty</groupId> <artifa…

    Java 2023年5月26日
    00
  • Spring MVC学习笔记之Controller查找(基于Spring4.0.3)

    以下是关于“Spring MVC学习笔记之Controller查找(基于Spring4.0.3)”的完整攻略,其中包含两个示例。 Spring MVC学习笔记之Controller查找(基于Spring4.0.3) 在Spring MVC中,Controller是处理HTTP请求的核心组件。在本文中,我们将讲解如何在Spring MVC中查找Controll…

    Java 2023年5月17日
    00
  • springboot中关于自动建表,无法更新字段的问题

    在Spring Boot中使用JPA进行开发时,可以通过使用Hibernate的hbm2ddl自动生成数据库表。在生成表之后,如果对实体类进行了更改,比如增加或修改了字段,当再次运行应用程序时,Hibernate并不会根据实体类的更改来更新数据库中的表结构,导致无法使用新的字段。为了解决这个问题,我们需要对Spring Boot的自动建表进行配置。 步骤如下…

    Java 2023年5月20日
    00
  • jdk安装、Java环境配置方法详解

    JDK安装、Java环境配置方法详解 什么是JDK? Java Development Kit(JDK)是一个开发环境,它允许开发人员创建Java应用程序并将其部署到不同的运行环境中,例如桌面和服务器。 JDK包含Java Runtime Environment(JRE)以及开发人员需要创建Java应用程序和Applet的工具。 JDK安装步骤 下载JDK安…

    Java 2023年5月23日
    00
  • JavaWeb 入门:Hello Servlet

    创建JavaWeb项目 打开Eclipse 点击菜单栏“File”->“New”->“Dynamic Web Project” 输入项目名称,然后点击“Next”按钮 选择“Generate web.xml deployment descriptor”,然后点击“Finish”按钮 添加Servlet 在“Package Explorer”视图中…

    Java 2023年6月16日
    00
合作推广
合作推广
分享本页
返回顶部