SpringBoot REST API + JWT + Spring Security教程

栏目: Java · 发布时间: 5年前

内容简介:如果您是JWTs Token的新手,我们将学习如何使用Spring安全性和JWT(JSON Web令牌)保护Spring启动REST API。首先从Github

如果您是JWTs Token的新手,我们将学习如何使用Spring安全性和JWT(JSON Web令牌)保护Spring启动REST API。

首先从Github Spring Boot REST API 克隆以下springBoot项目,步骤:

  1. 添加Maven依赖项。
  2. 更新现有用户模型
  3. 更新用户存储库
  4. 使用继承Spring UserDetailsS​​ervice实现UserDetailService
  5. 实现JWTAuthenticationFilter
  6. 实现JWTAuthorizationFilter
  7. 覆盖Spring Boot默认的Web安全配置
  8. 构建并运行项目。
  9. 测试

添加所需的Maven依赖关系

我们需要为现有的项目pom添加两个依赖项

  1. spring-boot-starter-security
  2. java-jwt
<!-- Spring Boot Security dependency-->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Java JWT dependency-->
<dependency>
   <groupId>com.auth0</groupId>
   <artifactId>java-jwt</artifactId>
   <version>3.4.1</version>
</dependency>

更新现有用户模型

接下来使用新属性用户名和密码更新现有用户模型,如下所示:

@Column(name = <font>"username"</font><font>, nullable = false, unique = <b>true</b>)
<b>private</b> String username;

@Column(name = </font><font>"password"</font><font>, nullable = false)
<b>private</b> String password;
</font>

更新现有的用户存储库

使用findByUsername方法更新现有的用户存储库。

<b>public</b> <b>interface</b> UserRepository <b>extends</b> JpaRepository<User, Long> {

  <font><i>/**
   * Find by username user.
   *
   * @param username the username
   * @return the user
   */</i></font><font>
  User findByUsername(String username);
}
</font>

使用继承Spring UserDetailsS​​ervice实现UserDetailService

为了使Spring Security能够认证用户详细信息,我们需要实现UserDetailService并覆盖loadUserByUsername以根据数据库验证用户详细信息。

@Service
<b>public</b> <b>class</b> UserDetailServiceImpl implements UserDetailsService {

    <b>private</b> UserRepository userRepository;

  <font><i>/**
   * Instantiates a new User detail service.
   *
   * @param userRepository the user repository
   */</i></font><font>
  <b>public</b> UserDetailServiceImpl(UserRepository userRepository) {
        <b>this</b>.userRepository = userRepository;
    }

    @Override
    <b>public</b> UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        User userDetails = userRepository.findByUsername(username);
        <b>if</b>(userDetails == <b>null</b>){
            <b>throw</b> <b>new</b> UsernameNotFoundException(username);
        }
        <b>return</b> <b>new</b> org.springframework.security.core.userdetails.User(userDetails.getUsername(),userDetails.getPassword(), <b>new</b> ArrayList<>());
    }
}
</font>

实现JWTAuthenticationFilter:

<b>public</b> <b>class</b> JWTAuthenticationFilter <b>extends</b> UsernamePasswordAuthenticationFilter {

  <b>public</b> <b>static</b> <b>final</b> String SECRET = <font>"SecretKeyToGenJWTs"</font><font>;
  <b>public</b> <b>static</b> <b>final</b> <b>long</b> EXPIRATION_TIME = 864_000_000; </font><font><i>// 10 days</i></font><font>
  <b>public</b> <b>static</b> <b>final</b> String TOKEN_PREFIX = </font><font>"Bearer "</font><font>;
  <b>public</b> <b>static</b> <b>final</b> String HEADER_STRING = </font><font>"Authorization"</font><font>;

  <b>private</b> AuthenticationManager authenticationManager;

  <b>public</b> JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
    <b>this</b>.authenticationManager = authenticationManager;
  }

  @Override
  <b>public</b> Authentication attemptAuthentication(
      HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    <b>try</b> {

      com.staxrt.tutorial.model.User loginUser = <b>new</b> ObjectMapper().readValue(request.getInputStream(), com.staxrt.tutorial.model.User.<b>class</b>);

      <b>return</b> authenticationManager.authenticate(
          <b>new</b> UsernamePasswordAuthenticationToken(
              loginUser.getUsername(), loginUser.getPassword(), <b>new</b> ArrayList<>()));
    } <b>catch</b> (IOException e) {
      <b>throw</b> <b>new</b> RuntimeException(e);
    }
  }

  @Override
  <b>protected</b> <b>void</b> successfulAuthentication(
      HttpServletRequest request,
      HttpServletResponse response,
      FilterChain chain,
      Authentication authResult)
      throws IOException, ServletException {
    String token =
        JWT.create()
            .withSubject(
                ((User) authResult.getPrincipal()).getUsername()) </font><font><i>// Payload register sub claim</i></font><font>
            .withExpiresAt(
                <b>new</b> Date(System.currentTimeMillis() + EXPIRATION_TIME)) </font><font><i>// JWT token validity time</i></font><font>
            .sign(Algorithm.HMAC512(SECRET.getBytes())); </font><font><i>// JWT Signature</i></font><font>
    response.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
  }
}
</font>

实现JWTAuthorizationFilter

<b>public</b> <b>class</b> JWTAuthenticationFilter <b>extends</b> UsernamePasswordAuthenticationFilter {

  <b>public</b> <b>static</b> <b>final</b> String SECRET = <font>"SecretKeyToGenJWTs"</font><font>;
  <b>public</b> <b>static</b> <b>final</b> <b>long</b> EXPIRATION_TIME = 864_000_000; </font><font><i>// 10 days</i></font><font>
  <b>public</b> <b>static</b> <b>final</b> String TOKEN_PREFIX = </font><font>"Bearer "</font><font>;
  <b>public</b> <b>static</b> <b>final</b> String HEADER_STRING = </font><font>"Authorization"</font><font>;

  <b>private</b> AuthenticationManager authenticationManager;

  <b>public</b> JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
    <b>this</b>.authenticationManager = authenticationManager;
  }

  @Override
  <b>public</b> Authentication attemptAuthentication(
      HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    <b>try</b> {

      com.staxrt.tutorial.model.User loginUser = <b>new</b> ObjectMapper().readValue(request.getInputStream(), com.staxrt.tutorial.model.User.<b>class</b>);

      <b>return</b> authenticationManager.authenticate(
          <b>new</b> UsernamePasswordAuthenticationToken(
              loginUser.getUsername(), loginUser.getPassword(), <b>new</b> ArrayList<>()));
    } <b>catch</b> (IOException e) {
      <b>throw</b> <b>new</b> RuntimeException(e);
    }
  }

  @Override
  <b>protected</b> <b>void</b> successfulAuthentication(
      HttpServletRequest request,
      HttpServletResponse response,
      FilterChain chain,
      Authentication authResult)
      throws IOException, ServletException {
    String token =
        JWT.create()
            .withSubject(
                ((User) authResult.getPrincipal()).getUsername()) </font><font><i>// Payload register sub claim</i></font><font>
            .withExpiresAt(
                <b>new</b> Date(System.currentTimeMillis() + EXPIRATION_TIME)) </font><font><i>// JWT token validity time</i></font><font>
            .sign(Algorithm.HMAC512(SECRET.getBytes())); </font><font><i>// JWT Signature</i></font><font>
    response.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
  }
}
</font>

覆盖Spring Boot默认的Web安全配置

这样我们可以将自己的身份认证逻辑注入JWT toknbase

@EnableWebSecurity
<b>public</b> <b>class</b> WebSecurity <b>extends</b> WebSecurityConfigurerAdapter {

  <b>public</b> <b>static</b> <b>final</b> String SIGN_UP_URL = <font>"/api/v1/users"</font><font>;

  @Autowired <b>private</b> UserDetailServiceImpl userDetailService;

  @Autowired <b>private</b> BCryptPasswordEncoder bCryptPasswordEncoder;

  <b>public</b> WebSecurity(
      UserDetailServiceImpl userDetailService, BCryptPasswordEncoder bCryptPasswordEncoder) {
    <b>this</b>.userDetailService = userDetailService;
    <b>this</b>.bCryptPasswordEncoder = bCryptPasswordEncoder;
  }

  @Override
  <b>protected</b> <b>void</b> configure(HttpSecurity http) throws Exception {
    http.cors()
        .and()
        .csrf()
        .disable()
        .authorizeRequests() </font><font><i>// Add a new custom security filter</i></font><font>
        .antMatchers(HttpMethod.POST, SIGN_UP_URL)
        .permitAll() </font><font><i>// Only Allow Permission for create user endpoint</i></font><font>
        .anyRequest()
        .authenticated()
        .and()
        .addFilter(<b>this</b>.getJWTAuthenticationFilter()) </font><font><i>// Add JWT Authentication Filter</i></font><font>
        .addFilter(
            <b>new</b> JWTAuthorizationFilter(authenticationManager())) </font><font><i>// Add JWT Authorization Filter</i></font><font>
        .sessionManagement()
        .sessionCreationPolicy(
            SessionCreationPolicy.STATELESS); </font><font><i>// this disables session creation on Spring Security</i></font><font>
  }

  @Bean
  CorsConfigurationSource corsConfigurationSource() {
    <b>final</b> UrlBasedCorsConfigurationSource source = <b>new</b> UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration(
        </font><font>"/**"</font><font>,
        <b>new</b> CorsConfiguration()
            .applyPermitDefaultValues()); </font><font><i>// Allow/restrict our CORS permitting requests from any</i></font><font>
                                          </font><font><i>// source</i></font><font>
    <b>return</b> source;
  }

  <b>public</b> JWTAuthenticationFilter getJWTAuthenticationFilter() throws Exception {
    <b>final</b> JWTAuthenticationFilter filter = <b>new</b> JWTAuthenticationFilter(authenticationManager());
    filter.setFilterProcessesUrl(</font><font>"/api/v1/auth/login"</font><font>); </font><font><i>// override the default spring login url</i></font><font>
    <b>return</b> filter;
  }
}
</font>

构建并运行项目

mvn package

java -jar target/spring-boot-rest-api-auth-jwt-tutorial-0.0.1-SNAPSHOT.jar

或者,您可以在不使用package 的情况下运行应用程序 -

mvn spring-boot:run

运行 http://localhost:8080 .

测试:

POST http:<font><i>//localhost:8080/api/v1/users</i></font><font>

Request
{
   </font><font>"username"</font><font>: </font><font>"givantha90"</font><font>,
   </font><font>"password"</font><font>: </font><font>"welcome@123"</font><font>,
    </font><font>"firstName"</font><font>: </font><font>"Givantha"</font><font>,
    </font><font>"lastName"</font><font>: </font><font>"Kalansuriya"</font><font>,
    </font><font>"email"</font><font>: </font><font>"givanhta@gmail.com"</font><font>,
    </font><font>"createdBy"</font><font>: </font><font>"Givantha"</font><font>,
    </font><font>"updatedBy"</font><font>: </font><font>"Givantha"</font><font>
}

Resonse
{
    </font><font>"id"</font><font>: 13,
    </font><font>"username"</font><font>: </font><font>"givantha9110"</font><font>,
    </font><font>"firstName"</font><font>: </font><font>"Givantha"</font><font>,
    </font><font>"lastName"</font><font>: </font><font>"Kalansuriya"</font><font>,
    </font><font>"email"</font><font>: </font><font>"givanhta@gmail.com"</font><font>,
    </font><font>"createdAt"</font><font>: </font><font>"2018-11-24T15:20:19.463+0000"</font><font>,
    </font><font>"createdBy"</font><font>: </font><font>"Givantha"</font><font>,
    </font><font>"updatedAt"</font><font>: </font><font>"2018-11-24T15:20:19.463+0000"</font><font>,
    </font><font>"updatedBy"</font><font>: </font><font>"Givantha"</font><font>
}

POST  http:</font><font><i>//localhost:8080/api/v1/auth/login</i></font><font>

Request

{
    </font><font>"username"</font><font>: </font><font>"givantha12"</font><font>,
    </font><font>"password"</font><font>: </font><font>"welcome@123"</font><font>
}
</font>

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

大连接

大连接

[美] 尼古拉斯•克里斯塔基斯(Nicholas A. Christakis)、[美] 詹姆斯•富勒(James H. Fowler) / 简学 / 中国人民大学出版社 / 2013-1 / 59.90元

[内容简介] 1. 本书是继《六度分隔》之后,社会科学领域最重要的作品。作者发现:相距三度之内是强连接,强连接可以引发行为;相聚超过三度是弱连接,弱连接只能传递信息。 2. 本书讲述了社会网络是如何形成的以及对人类现实行为的影响,如对人类的情绪、亲密关系、健康、经济的运行和政治的影响等,并特别指出,三度影响力(即朋友的朋友的朋友也能影响到你)是社会化网络的强连接原则,决定着社会化网络的......一起来看看 《大连接》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

SHA 加密
SHA 加密

SHA 加密工具