401を与えるSpring Bootベアラートークン認証

kk1957:

Spring bootは初めてなので手伝ってください。Bearer Token認証れていないリクエストでを生成できるようになりました次に、このトークンをエンドポイントで使用して、リクエストが認証されるようにしたい-これが私の問題の原因です。常に401を取得していますが、構成に問題があるようです。これが私のコードです

public class ApplicationUser {

private String username;
private String password;
private String role;

public ApplicationUser(String username, String password, String role) {
    this.username = username;
    this.password = password;
    this.role = role;
}

public String getUsername() {
    return username;
}

public String getPassword() {
    return password;
}

public String getRole() {
    return role;
    }
}

JwtConfigクラス:

@Component("jwtConfig")
public class JwtConfig {
@Value("${security.jwt.uri:/auth/**}")
private String Uri;

@Value("${security.jwt.header:Authorization}")
private String header;

@Value("${security.jwt.prefix:Bearer }")
private String prefix;

@Value("${security.jwt.expiration:#{24*60*60}}")
private int expiration;

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

public String getUri() {
    return Uri;
}

public String getHeader() {
    return header;
}

public String getPrefix() {
    return prefix;
}

public int getExpiration() {
    return expiration;
}

public String getSecret() {
    return secret;
}
}

JwtTokenAuthenticationFilter

public class JwtTokenAuthenticationFilter extends  OncePerRequestFilter {

private final JwtConfig jwtConfig;

public JwtTokenAuthenticationFilter(JwtConfig jwtConfig) {
    this.jwtConfig = jwtConfig;
}

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
        throws ServletException, IOException {

    // 1. get the authentication header. Tokens are supposed to be passed in the authentication header
    String header = request.getHeader(jwtConfig.getHeader());

    // 2. validate the header and check the prefix
    if(header == null || !header.startsWith(jwtConfig.getPrefix())) {
        chain.doFilter(request, response);          // If not valid, go to the next filter.
        return;
    }

    // If there is no token provided and hence the user won't be authenticated.
    // It's Ok. Maybe the user accessing a public path or asking for a token.

    // All secured paths that needs a token are already defined and secured in config class.
    // And If user tried to access without access token, then he won't be authenticated and an exception will be thrown.

    // 3. Get the token
    String token = header.replace(jwtConfig.getPrefix(), "");

    try {   // exceptions might be thrown in creating the claims if for example the token is expired

        // 4. Validate the token
        Claims claims = Jwts.parser()
                .setSigningKey(jwtConfig.getSecret().getBytes())
                .parseClaimsJws(token)
                .getBody();

        String username = claims.getSubject();
        if(username != null) {
            @SuppressWarnings("unchecked")
            List<String> authorities = (List<String>) claims.get("authorities");

            // 5. Create auth object
            // UsernamePasswordAuthenticationToken: A built-in object, used by spring to represent the current authenticated / being authenticated user.
            // It needs a list of authorities, which has type of GrantedAuthority interface, where SimpleGrantedAuthority is an implementation of that interface
            UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
                    username, null, authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()));

            // 6. Authenticate the user
            // Now, user is authenticated
            SecurityContextHolder.getContext().setAuthentication(auth);
        }

    } catch (Exception e) {
        // In case of failure. Make sure it's clear; so guarantee user won't be authenticated
        SecurityContextHolder.clearContext();
    }

    // go to the next filter in the filter chain
    chain.doFilter(request, response);
}

}

JwtUsernameAndPasswordAuthenticationFilter

public class JwtUsernameAndPasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter   {

// We use auth manager to validate the user credentials
private AuthenticationManager authManager;

private final JwtConfig jwtConfig;

public JwtUsernameAndPasswordAuthenticationFilter(AuthenticationManager authManager, JwtConfig jwtConfig) {
    this.authManager = authManager;
    this.jwtConfig = jwtConfig;

    // By default, UsernamePasswordAuthenticationFilter listens to "/login" path.
    // In our case, we use "/auth". So, we need to override the defaults.
    this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(jwtConfig.getUri(), "POST"));
}

@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
        throws AuthenticationException {

    try {

        // 1. Get credentials from request
        UserCredentials creds = new ObjectMapper().readValue(request.getInputStream(), UserCredentials.class);

        // 2. Create auth object (contains credentials) which will be used by auth manager
        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                creds.getUsername(), creds.getPassword(), Collections.emptyList());

        // 3. Authentication manager authenticate the user, and use UserDetialsServiceImpl::loadUserByUsername() method to load the user.
        return authManager.authenticate(authToken);

    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

// Upon successful authentication, generate a token.
// The 'auth' passed to successfulAuthentication() is the current authenticated user.
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
                                        Authentication auth) throws IOException, ServletException {

    Long now = System.currentTimeMillis();
    String token = Jwts.builder()
            .setSubject(auth.getName())
            // Convert to list of strings.
            // This is important because it affects the way we get them back in the Gateway.
            .claim("authorities", auth.getAuthorities().stream()
                    .map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
            .setIssuedAt(new Date(now))
            .setExpiration(new Date(now + jwtConfig.getExpiration() * 1000))  // in milliseconds
            .signWith(SignatureAlgorithm.HS512, jwtConfig.getSecret().getBytes())
            .compact();

    // Add token to header
    response.addHeader(jwtConfig.getHeader(), jwtConfig.getPrefix() + token);
}

// A (temporary) class just to represent the user credentials
private static class UserCredentials {
    private String username, password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
}

SecurityCredentialsConfig

@Configuration
@EnableWebSecurity(debug=true)
public class SecurityCredentialsConfig extends WebSecurityConfigurerAdapter {

@Autowired
private UserDetailsServiceImpl userDetailsService;

@Autowired
private JwtConfig jwtConfig;

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .csrf().disable()
            // make sure we use stateless session; session won't be used to store user's state.
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            // handle an authorized attempts
            .exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
            .and()
            // Add a filter to validate user credentials and add token in the response header

            // What's the authenticationManager()?
            // An object provided by WebSecurityConfigurerAdapter, used to authenticate the user passing user's credentials
            // The filter needs this auth manager to authenticate the user.
            .addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig))
            .authorizeRequests()
            // allow all POST requests
            .antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()
            // any other requests must be authenticated
          //  .antMatchers(HttpMethod.GET, "/v1/**").hasRole("USER")
            .anyRequest().authenticated();
}

// Spring has UserDetailsService interface, which can be overriden to provide our implementation for fetching user from database (or any other source).
// The UserDetailsService object is used by the auth manager to load the user from database.
// In addition, we need to define the password encoder also. So, auth manager can compare and verify passwords.
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}

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

UserDetailsS​​erviceImpl

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

@Autowired
private BCryptPasswordEncoder encoder;

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    final List<ApplicationUser> users = Arrays.asList(
            new ApplicationUser("omar",encoder.encode("12345"), "USER"),
            new ApplicationUser("admin", encoder.encode("12345"), "ADMIN")
    );

    for(ApplicationUser appUser: users) {
        if(appUser.getUsername().equals(username)) {
            List<GrantedAuthority> grantedAuthorities = AuthorityUtils
                    .commaSeparatedStringToAuthorityList( appUser.getRole());

            return new User(appUser.getUsername(), appUser.getPassword(), grantedAuthorities);
        }
    }

    // If user not found. Throw this exception.
    throw new UsernameNotFoundException("Username: " + username + " not found");

}
}

Webセキュリティ

@EnableWebSecurity(debug=true)
@Order(1000)
public class WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private JwtConfig jwtConfig;

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .csrf().disable()
            // make sure we use stateless session; session won't be used to store user's state.
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            // handle an authorized attempts
            .exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
            .and()
            // Add a filter to validate the tokens with every request
            .addFilterAfter(new JwtTokenAuthenticationFilter(jwtConfig), UsernamePasswordAuthenticationFilter.class)
            // authorization requests config
            .authorizeRequests()
            // allow all who are accessing "auth" service
            .antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()
            // must be an admin if trying to access admin area (authentication is also required here)
            .antMatchers("/v1/cooks").access("hasRole('ADMIN')")
            //for other uris
         //   .antMatchers(HttpMethod.GET, "/v1/**").hasRole("USER")
            // Any other request must be authenticated
            .anyRequest().authenticated();
}

}

コントローラ

@RestController


public class CookController {

@Autowired
private CookService cookService;
// Get All Cooks
@GetMapping("/v1/cooks")
public List<Cook> getAllCooks(){
    return cookService.getAllCooks();
}

application.properties

zuul.routes.auth-service.path=/auth/**
zuul.routes.auth-service.service-id=AUTH-SERVICE
zuul.routes.auth-service.strip-prefix=false
zuul.routes.auth-service.sensitive-headers=Cookie,Set-Cookie  

spring.application.name=auth-service
server.port=9100
eureka.client.service-url.default-zone=http://localhost:8761/eureka

への呼び出しはv1/cooks常に401を返します。構成のどの部分が欠けていますか?https://medium.com/omarelgabrys-blog/microservices-with-spring-boot-authentication-with-jwt-part-3-fafc9d7187e8にあるドキュメントをフォローしました

しかし、私は今完全に迷っています。リクエストURLはGET http://localhost:9100/v1/cooks

レスポンスは

{ "timestamp": "2018-10-13T20:08:13.804+0000", "status": 401, "error": "Unauthorized", "message": "No message available", "path": "/v1/cooks" }

pom.xml

 <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.restdocs</groupId>
        <artifactId>spring-restdocs-mockmvc</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.16</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.3.0-b170201.1204</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>java-jwt</artifactId>
        <version>3.4.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

編集:pomからapplication.propertiesと依存関係を追加しました

kj007:

要件を見ると、複数のパスに複数の認証を使用するまで(JWTが必要なパスや、基本的な認証または認証2が必要なパスなど)、複数のhttpセキュリティ構成は実際には必要ありません。

だから削除SecurityCredentialsConfigWebSecurityて以下に更新してください。

@Configuration
@EnableWebSecurity(debug = true)    // Enable security config. This annotation denotes config for spring security.
public class WebSecurity extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtConfig jwtConfig;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                // make sure we use stateless session; session won't be used to store user's state.
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                // authorization requests config
                .authorizeRequests()
                // allow all who are accessing "auth" service
                .antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()
                // must be an admin if trying to access admin area (authentication is also required here)
                .antMatchers("/v1/cooks/**").hasAuthority("ADMIN")
                //for other uris
                //   .antMatchers(HttpMethod.GET, "/v1/**").hasRole("USER")
                // Any other request must be authenticated
                .anyRequest().authenticated()
                .and()
                // handle an authorized attempts
                .exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
                .and()
                // Add a filter to validate the tokens with every request
                .addFilterAfter(new JwtTokenAuthenticationFilter(jwtConfig), UsernamePasswordAuthenticationFilter.class)
                .addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig));
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

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

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

JWTベアラートークンを使用した認証Swagger

分類Dev

Spring Boot Keycloak-ベアラートークンを確認する方法は?

分類Dev

Spring Boot Keycloak-ベアラートークンを確認する方法は?

分類Dev

ベアラートークン認証の使用中にasp.netCORE2認証Cookieを設定する

分類Dev

nodejsを介したベアラートークンを使用したGoogleCloud認証

分類Dev

Javascriptを介した認証トークンベアラーの送信

分類Dev

ベアラートークン認証(JWT)のspringdoc-openapi-uiで承認ボタンを有効にする

分類Dev

asp.netvnextでベアラートークン認証を使用してトークンを更新します

分類Dev

クライアントアプリでfirebaseのプライベート認証情報を非表示にする

分類Dev

クライアントアプリでfirebaseのプライベート認証情報を非表示にする

分類Dev

kubeletサーバーのベアラートークン認証を有効にする

分類Dev

OWINJWTベアラー認証を使用してRS256署名付きJWTトークンを確認します

分類Dev

ベアラートークンをMVCアプリの認証Cookieに変換する方法

分類Dev

JenkinsがKubernetesプラグイン認証ベアラートークンをログに印刷

分類Dev

JQueryAjaxを介した認証トークンベアラーの送信-バックエンドは.NETCore WebApiです

分類Dev

nodejsでベアラートークンを使用してsocket.io認証を実装する方法

分類Dev

ポリシーベースの承認を追加すると、JWTベアラートークン認証チェックがスキップされますか?

分類Dev

JWTベアラー認証はヘッダーからトークンを読み取りません

分類Dev

Delphiアプリクライアント、認証ベースを使用したWSDL-SOAPのクエリ

分類Dev

Spring BootWebサービスクライアント認証

分類Dev

JWTキーローテーションをサポートするベアラートークン認証用のOwinミドルウェア

分類Dev

ベアラートークンを使用したIBMCloud Speech-to-TextSDK認証の失敗

分類Dev

HttpClientが.NetCore3.1で認証ベアラートークンを送信しない

分類Dev

ジャージによるクライアント認証

分類Dev

OpenIdConnectとangularjsを使用したAsp.netコアトークンベースのクレーム認証:ベアラーは禁止されていました

分類Dev

クライアントモードのOpenSSL:認証を確認する

分類Dev

カスタム認証を使用してクラウドエンドポイントのベアラートークンを作成する

分類Dev

プレーンなJavascript / AJAXを使用してクライアント側のトークンベースの認証を実装する

分類Dev

Spring Bootを使用したSpring Security:基本認証とJWTトークン認証を組み合わせる

Related 関連記事

  1. 1

    JWTベアラートークンを使用した認証Swagger

  2. 2

    Spring Boot Keycloak-ベアラートークンを確認する方法は?

  3. 3

    Spring Boot Keycloak-ベアラートークンを確認する方法は?

  4. 4

    ベアラートークン認証の使用中にasp.netCORE2認証Cookieを設定する

  5. 5

    nodejsを介したベアラートークンを使用したGoogleCloud認証

  6. 6

    Javascriptを介した認証トークンベアラーの送信

  7. 7

    ベアラートークン認証(JWT)のspringdoc-openapi-uiで承認ボタンを有効にする

  8. 8

    asp.netvnextでベアラートークン認証を使用してトークンを更新します

  9. 9

    クライアントアプリでfirebaseのプライベート認証情報を非表示にする

  10. 10

    クライアントアプリでfirebaseのプライベート認証情報を非表示にする

  11. 11

    kubeletサーバーのベアラートークン認証を有効にする

  12. 12

    OWINJWTベアラー認証を使用してRS256署名付きJWTトークンを確認します

  13. 13

    ベアラートークンをMVCアプリの認証Cookieに変換する方法

  14. 14

    JenkinsがKubernetesプラグイン認証ベアラートークンをログに印刷

  15. 15

    JQueryAjaxを介した認証トークンベアラーの送信-バックエンドは.NETCore WebApiです

  16. 16

    nodejsでベアラートークンを使用してsocket.io認証を実装する方法

  17. 17

    ポリシーベースの承認を追加すると、JWTベアラートークン認証チェックがスキップされますか?

  18. 18

    JWTベアラー認証はヘッダーからトークンを読み取りません

  19. 19

    Delphiアプリクライアント、認証ベースを使用したWSDL-SOAPのクエリ

  20. 20

    Spring BootWebサービスクライアント認証

  21. 21

    JWTキーローテーションをサポートするベアラートークン認証用のOwinミドルウェア

  22. 22

    ベアラートークンを使用したIBMCloud Speech-to-TextSDK認証の失敗

  23. 23

    HttpClientが.NetCore3.1で認証ベアラートークンを送信しない

  24. 24

    ジャージによるクライアント認証

  25. 25

    OpenIdConnectとangularjsを使用したAsp.netコアトークンベースのクレーム認証:ベアラーは禁止されていました

  26. 26

    クライアントモードのOpenSSL:認証を確認する

  27. 27

    カスタム認証を使用してクラウドエンドポイントのベアラートークンを作成する

  28. 28

    プレーンなJavascript / AJAXを使用してクライアント側のトークンベースの認証を実装する

  29. 29

    Spring Bootを使用したSpring Security:基本認証とJWTトークン認証を組み合わせる

ホットタグ

アーカイブ