当前位置: 首页 > 知识库问答 >
问题:

即使凭据为真,Spring Boot Security也会在API调用上引发401身份验证错误

席俊驰
2023-03-14

我正在与Spring Boot开发一个单页应用程序

然后,我将应用程序打包并作为WAR部署到应用服务器/servlet容器等。应用程序开始拒绝来自firefox上我的客户端和rest客户端“rest client”的authenticated()请求。我已经通过我的JwtFilter监控了请求,它不是错误的凭证。

我尝试使用Glassfish 4.1.2(build 1)中的其余endpoint,但没有运气。同样由于一些神秘的原因server.logglassfish被[Thread-8]淹没unknown.jul.logger-时间戳...相同...输出,因此目前没有服务器输出与请求拒绝有关,我还在Apache Tomcat 8.5.23上部署了该应用程序,请求安全资源时的错误消息如下:

JwtAuthenticationEntryPoint      : Responding with unauthorized error. Message - Full authentication is required to access this resource

我的应用程序应该保护除/api/auth/**下的请求之外的所有请求,并且在IntelliJ调试模式下在嵌入式tomcat上运行的情况下完美地做到了这一点。我以前从客户端代码(使用axios)和RESTClient调用服务器如下:

(GET) http://localhost:8080/api/user/me

在app.server/web容器上:

(GET) http://localhost:8080/myproject/api/user/me

问题是,安全restendpoint在IntelliJ调试模式下接受嵌入式tomcat上的认证请求,在WAR部署后,它神秘地拒绝了所有安全请求。

我遵循了spring docs中关于使用maven进行WAR打包的步骤,GitHub页面上关于glassfish、tomcat、wildfly等的spring boot部署测试的步骤..并以一个基类如下的项目结束:

主类(带@SpringBootApplication)

@SpringBootApplication
@EntityScan(basePackageClasses = {
        AccountingApplication.class,
        Jsr310JpaConverters.class
})
public class AccountingApplication extends SpringBootServletInitializer{

    @PostConstruct
    void init() {
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
    }

    public static void main(String[] args) {
        SpringApplication.run(applicationClass, args);
    }

    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(applicationClass);
    }

    private static Class<AccountingApplication> applicationClass = AccountingApplication.class;
}

下面是我的安全配置,

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
    securedEnabled = true,
    jsr250Enabled = true,
    prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
CustomUserDetailsService userDetailsService;

@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;

@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
    return new JwtAuthenticationFilter();
}

@Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
    authenticationManagerBuilder.
            userDetailsService(userDetailsService).
            passwordEncoder(passwordEncoder());

}

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

@Bean
public PasswordEncoder passwordEncoder() {
    /* removed for clarity */
}

@Override
protected void configure(HttpSecurity http) throws Exception {

    http
            .cors()
                .and()
            .csrf()
                .disable()
            .exceptionHandling()
                .authenticationEntryPoint(unauthorizedHandler)
                .and()
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
            .authorizeRequests()
                .antMatchers("/resources/**")
                    .permitAll()
                .antMatchers("/",
                        "/favicon.ico",
                        "/**/*.png",
                        "/**/*.gif",
                        "/**/*.svg",
                        "/**/*.woff",
                        "/**/*.woff2",
                        "/**/*.ttf",
                        "/**/*.eot",
                        "/**/*.jpg",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js")
                    .permitAll()
                .antMatchers("/api/auth/**")
                    .permitAll()
                .anyRequest()
                    .authenticated();

    http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}

}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.my.project</groupId>
<artifactId>myproject-web</artifactId>
<version>1.0</version>
<packaging>war</packaging>

<name>myproject-web</name>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
    <relativePath/>
</parent>

<properties>
    <start-class>com.my.MainApplication</start-class>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-rest</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-hateoas</artifactId>
    </dependency>
    
    <!-- Exclusion of artifacts as instructed in Spring Boot deployment docs -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.hibernate.validator</groupId>
                <artifactId>hibernate-validator</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <!-- Provided scope because of the dependency collision during WAR deployment -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <scope>provided</scope>
    </dependency>

    <!-- To access DB -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    
    <!-- utilities -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.0</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>       
</dependencies>
<build>
    <finalName>myproject</finalName>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <addResources>true</addResources>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-failsafe-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>integration-test</goal>
                        <goal>verify</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

application.properties

spring.data.rest.base-path=/api

spring.datasource.url=jdbc:mysql://localhost:3306/myDB?useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=1234

spring.jpa.hibernate.ddl-auto=none
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.show-sql = true
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

logging.level.org.hibernate.SQL= DEBUG
# App properties
app.jwtSecret= jwtSecretKey
app.jwtExpirationInMs = 604800000

一个行为不当的控制器

@RestController
@RequestMapping("/api")
public class UserController {

    @GetMapping("/user")
    public UserProfile getCurrentUser(@CurrentUser UserPrincipal currentUser) {
        UserProfile userSummary = new UserProfile(currentUser.getId(), currentUser.getUsername(), currentUser.getName());
        return userSummary;
    }
}

最后,如果有人想知道定制过滤是否会干扰预期的流,我将在容器引导期间给出过滤器配置。

o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'errorPageFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
.s.DelegatingFilterProxyRegistrationBean : Mapping filter: 'springSecurityFilterChain' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'jwtAuthenticationFilter' to: [/*]
o.s.b.w.servlet.ServletRegistrationBean  : Servlet dispatcherServlet mapped to [/]

Spring Boot 版本 2.0.1-RELEASE 内部版本管理工具: Maven

很抱歉写了这么长的帖子,有什么我可以提供的,请在评论中提问。

共有1个答案

斜单鹗
2023-03-14

所以,我在问题的评论中解释了tomcat和glassfish的问题,我想分享一下关于Wildfly部署的细节。

我使用Wildfly版本10.1.Final进行部署,也用11.0.Final进行了测试,并且不认为它会在部署到12.0.Final时造成任何麻烦。

为了能够部署,您需要主类的上述SpringBootServletInitializer扩展,并且您需要在POM中具有以下结构。

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.hibernate.validator</groupId>
                <artifactId>hibernate-validator</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <!-- Provided scope because of the dependency collision during WAR deployment -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <scope>provided</scope>
    </dependency>

默认情况下,wildfly 10.1.Final使用Hibernate Validator 5.x.Final和Bean Validation 1.1以及<code>spring boot starter web

因此,为了在服务器调用过程中部署并避免由于某些验证错误而崩溃,您需要使hibernate validator

如果有人想分享他们对未解决问题的智慧,他们非常受欢迎。

 类似资料:
  • 我正在尝试使用Apache Flume将推文保存到HDFS。我目前在Hadoop和Flume中使用Cloudera图像。我在Cloudera的博客上学习教程,但我无法连接到Twitter API。 我收到以下错误: 我已经将我的twitter API凭证复制到flume.conf中(我已经在光盘和web用户界面上进行了尝试)。我也曾试图重新生成它们,并复制那些新的,但这对我没有帮助。 我的pom。

  • 问题内容: 我正在使用HP ALM版本12.55.113。我正在尝试通过REST- API自动上传测试结果。经过身份验证并尝试读取一个简单的缺陷后,我收到了401未经身份验证的错误。我使用以下示例代码检索有效的LWSSO和QCSession Cookie: 我得到以下控制台输出: 登录:InboundJaxrsResponse {context = ClientResponse {method =

  • 我对社交网络分析和twitter api是新手。我想收集关于特定主题的tweets。所以我写了下面的代码 在我的程序中,我需要在哪里提供凭据 谢谢

  • 我目前正在使用ASP开发一个网站。net MVC框架,我决定停止使用本地数据库,并在azure上发布我的web应用程序及其关联数据库。现在我有一个奇怪的身份验证问题。身份IsAuthenticated总是正确的。起初,我得到了以下错误: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier或http://schem

  • 我试图在一个反应式Spring Boot应用程序中配置一个Spring Security性,该应用程序具有一个Vuejs前端,在未经身份验证时将用户重定向到外部OpenID提供程序(用于身份验证)。在用户通过OpenID提供程序进行身份验证并重定向回应用程序(前端)后,将根据OpenID提供程序的响应创建用户名密码身份验证令牌(身份验证),并手动进行身份验证。 但是,在执行此操作时,应用程序似乎无