带有 JWT 的 Spring Security OAuth2 重定向到登录页面

Posted

技术标签:

【中文标题】带有 JWT 的 Spring Security OAuth2 重定向到登录页面【英文标题】:Spring Security OAuth2 with JWT redirect to login page 【发布时间】:2020-01-12 21:55:17 【问题描述】:

我使用 OAuth2 和 JWT 创建了 Spring Security 应用程序。当它运行时,我得到一个登录页面。 下面我提到了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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.RELEASE</version>
    </parent>
    <groupId>com.java.oauth</groupId>
    <artifactId>AuthorizationWithOauth2nJWT</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>AuthorizationWithOauth2nJWT</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.0.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-jwt</artifactId>
            <version>1.0.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

下面提到了AuthorizationServerConfig.java文件。

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter 

    private String clientId = "client-id";
    private String clientSecret = "my-secret";

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager getauthenticationManager;

    @Bean
    public JwtAccessTokenConverter tokenEnhancer() 
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("123");
        return converter;
    

    @Bean
    public JwtTokenStore tokenStore() 
        return new JwtTokenStore(tokenEnhancer());
    

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception 
        endpoints.authenticationManager(getauthenticationManager).tokenStore(tokenStore())
                .accessTokenConverter(tokenEnhancer());
    



    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception 
        security
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()");
    

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception 

        clients.inMemory()
                .withClient(clientId)
                .secret(clientSecret)
                .scopes("read", "write", "trust")
                .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
                .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
                .accessTokenValiditySeconds(20000)
                .refreshTokenValiditySeconds(20000);

    


这是 ResourceServerConfig.java 文件。

@Configuration
@EnableResourceServer
@Order(100)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter 

    @Override
    public void configure(HttpSecurity http) throws Exception 
        http.csrf().disable();

        http.requestMatchers().antMatchers("/oauth/**")
                .and()
                .authorizeRequests()
                .antMatchers("/oauth/**").authenticated();

    

这是 SecurityConfig.java 文件。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter 

    @Bean
    public PasswordEncoder encoder() 
        return new BCryptPasswordEncoder();
    

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http
                .authorizeRequests()
                .antMatchers("/oauth/token").permitAll()
                .antMatchers("/getuser").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin().permitAll()
                .and()
                .csrf().disable();
    

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


下面我提到了application.yml文件

server:
  port: 8081

spring:
  security:
    user:
      name: test
      password: test

security:
  oauth2:
    resource:
      filter-order: 3

我使用 postman 来执行 API。授权和请求正文定义如下图。

执行 API 后,我收到以下响应,状态码为 200。

<html>

<head>
    <title>Login Page</title>
</head>

<body onload='document.f.username.focus();'>
    <h3>Login with Username and Password</h3>
    <form name='f' action='/login' method='POST'>
        <table>
            <tr>
                <td>User:</td>
                <td><input type='text' name='username' value=''></td>
            </tr>
            <tr>
                <td>Password:</td>
                <td><input type='password' name='password'/></td>
            </tr>
            <tr>
                <td colspan='2'><input name="submit" type="submit" value="Login"/></td>
            </tr>
        </table>
    </form>
</body>

</html>

非常感谢任何解决此问题的帮助或解决方法。

【问题讨论】:

你真正想要什么?您是否想像使用 API 一样获取访问令牌/ID 令牌(例如:- 没有登录页面)? @KavinduDodanduwa 是的,我想要没有登录页面的访问令牌和刷新令牌。 【参考方案1】:

OP 真正想要的是获得一个访问令牌,就好像它是从 API 获得的一样。

为此,OAuth 2.0 定义了两种授权类型

    Client Credentials Grant Resource Owner Password Credentials Grant

在这两种情况下,您都会跳过登录屏幕并调用令牌端点来获取访问令牌。请阅读 RFC(上面的链接)以了解您应该在何时何地采用这些授权类型。

我不是 Spring 专家,因此我在这里链接到在网上找到的教程,该教程解释了 Spring 的两种授权。

password-grant client-grant

【讨论】:

这个链接对我很有帮助。谢谢 我的问题仍然没有解决。我尽力了,但我没有任何快乐的道路 @LakshithaGihan 你现在面对什么?一个小小的解释可以让知道 $subject 的人帮助你。 @Kavindu 还是同样的问题。我认为我的用户名和密码没有编码。因为我在另一个项目的 application.yml 文件中进行了所有配置,并且工作正常。但这不是一个好习惯。 @LakshithaGihan 你检查过 Postman 的编码支持吗?例如更改参数以作为表单帖子或 URL 编码发送?【参考方案2】:

我添加了 UserConfig.java 类并添加了以下代码。

PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();

     @Override
        public void init(AuthenticationManagerBuilder auth) throws Exception 

            auth
                    .inMemoryAuthentication()
                    .withUser("test")
                    .password(passwordEncoder.encode("test123"))
                    .roles("USER","ADMIN","MANAGER")
                    .authorities("CAN_READ","CAN_WRITE","CAN_DELETE");
        

在 AuthorizationServerConfig.java 类中,删除 public void configure(ClientDetailsS​​erviceConfigurer clients) 方法并添加以下代码。

@Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception 

        clients.inMemory()
                .withClient("client")
                .secret(passwordEncoder.encode("password"))
                .scopes("READ", "WRITE")
                .authorizedGrantTypes("password", "refresh_token", "id_token");


    

我在 application.yml 文件中删除了以下配置

spring:
  security:
    user:
      name: test
      password: test

下图中提到的成功响应。

【讨论】:

以上是关于带有 JWT 的 Spring Security OAuth2 重定向到登录页面的主要内容,如果未能解决你的问题,请参考以下文章

带有 JWT 令牌的 Spring Security 在每个请求上加载 spring UserDetails 对象

带有 JWT 令牌的 Spring Security 和 Websocket

带有 JWT 的 Spring Security Oauth2 真的是无状态的吗?

带有 JWT 的 Spring Security OAuth2 重定向到登录页面

使用带有spring security的keycloak JWT令牌时如何修复403

Spring Security 结合了 Container Security 和 JWT Token