spring security OAuth2 搭建资源服务器以及授权服务器/jdbc/jwt两种方案

一、认证服务器基于jdbc方式

如果不懂请移步上一篇文章:Spring security OAuth2 授权服务器搭建-CSDN博客

    在上一篇文章中,TokenStore的默认实现为 InHenoryTokenStore 即内存存储,对于 CLient 信息,userDetaitsServce 接负责从存储库中读取数据,在上面的案例中默认使用的也是 InHemoryCLientDetalsService 实现类。如果要想使用政据库存储,只要提供这些接口的实现类即可,而框架已经为我们写好 dbekenStore 和 dbcclientDetatsService

1.1 数据库所需表

我们使用spring security 自带的sql 语句生成对应的表结构,我们关注一下 oauth_client_details  这个表,这个表用来储存用户密钥信息,相当于前面的这个地方

clients.inMemory() //基于内存,后期可以入库查出来
        .withClient("client-lq")
        .secret(passwordEncoder.encode("secret-lq"))

-- 写入客户端信息
INSERT INTO oauth_client_details
VALUES ('client-id', NULL,'$2a$10$2McX6ml8CVK3RUNpLkX1zeQeNkrEvLCPOJ2hhpG18XMeIMbJWIJnK', 'read', 'authorization_code,refresh_token','http://www.baidu.com',NULL, NULL, NULL, NULL,NULL);

client_secret 需要加密存进去,否则会报不成功

--  structure for clientdetails

DROP TABLE IF EXISTS `clientdetails`;
CREATE TABLE clientdetails (
  appId                  varchar(256) NOT NULL,
  resourceIds            varchar(256)  DEFAULT NULL,
  appSecret              varchar(256)  DEFAULT NULL,
  scope                  varchar(256)  DEFAULT NULL,
  grantTypes             varchar(256)  DEFAULT NULL,
  redirectUrl            varchar(256)  DEFAULT NULL,
  authorities            varchar(256)  DEFAULT NULL,
  access_token_validity  int(11)       DEFAULT NULL,
  refresh_token_validity int(11)       DEFAULT NULL,
  additionalInformation  varchar(4096) DEFAULT NULL,
  autoApproveScopes      varchar(256)  DEFAULT NULL,
  
  PRIMARY KEY (appId)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;



-- Table structure for oauth_access_token
DROP TABLE IF EXISTS oauth_access_token;
CREATE TABLE oauth_access_token  (
  token_id varchar(256) DEFAULT NULL,
  token blob,
  authentication_id varchar(256) NOT NULL,
  user_name     varchar(256) DEFAULT NULL,
  client_id     varchar(256) DEFAULT NULL,
  authentication blob ,
  refresh_token  varchar(256) DEFAULT NULL,
  PRIMARY KEY (authentication_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


--  Table structure for oauth_approvals

DROP TABLE IF EXISTS  oauth_approvals;
CREATE TABLE oauth_approvals (
  userId varchar(256) DEFAULT NULL,
  clientId varchar(256) DEFAULT NULL,
  scope varchar(256) DEFAULT NULL,
  status varchar(10) DEFAULT NULL,
  expiresAt timestamp NOT NULL DEFAULT current_timestamp ON UPDATE current_timestamp,
  lastModifiedAt date null
)ENGINE=InnODB DEFAULT CHARSET=utf8mb4;



-- Table structure for oauth_client_details
DROP TABLE IF EXISTS oauth_client_details;
CREATE TABLE oauth_client_details (
  client_id               varchar(256) NOT NULL,
  resource_ids            varchar(256)  DEFAULT NULL,
  client_secret           varchar(256)  DEFAULT NULL,
  scope                   varchar(256)  DEFAULT NULL,
  authorized_grant_types  varchar(256)  DEFAULT NULL,
  web_server_redirect_uri varchar(256)  DEFAULT NULL,
  authorities             varchar(256)  DEFAULT NULL,
  access_token_validity   int(11)       DEFAULT NULL,
  refresh_token_validity  int(11)       DEFAULT NULL,
  additional_information  varchar(4096) DEFAULT NULL,
  autoapprove             varchar(256)  DEFAULT NULL,
  PRIMARY KEY (client_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;





--  Table structure for oauth_clienttoken
DROP TABLE IF EXISTS  oauth_client_token;
CREATE TABLE oauth_client_token (
  token_id          varchar(256) DEFAULT NULL,
  token             blob,
  authentication_id varchar(256) NOT NULL,
  user_nam          varchar(256) DEFAULT NULL,
  client_id         varchar(256) DEFAULT NULL,
  PRIMARY KEY (authentication_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


--  Table structure for oauth_code
DROP TABLE IF EXISTS oauth_code;
CREATE TABLE oauth_code (
  code           varchar(256) DEFAULT NULL,
  authentication blob
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


-- Table structure for oauth_refresh_token
DROP TABLE IF EXISTS  oauth_refresh_token;
CREATE TABLE oauth_refresh_token (
token_id varchar(256) DEFAULT NULL,
token blob,
authentication blob
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


select * from  oauth_refresh_token;

-- 写入客户端信息
INSERT INTO oauth_client_details
VALUES ('client-id', NULL,'$2a$10$2McX6ml8CVK3RUNpLkX1zeQeNkrEvLCPOJ2hhpG18XMeIMbJWIJnK', 'read', 'authorization_code,refresh_token','http://www.baidu.com',NULL, NULL, NULL, NULL,NULL);

1.2 认证服务器配置

@Configuration
@EnableAuthorizationServer  //指定当前应用为授权服务器
public class JdbcAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {


    private final PasswordEncoder passwordEncoder;
    private final UserDetailsService userDetailsService;
    private final AuthenticationManager authenticationManager;

    private final DataSource dataSource;

    @Autowired
    public JdbcAuthorizationServerConfig(PasswordEncoder passwordEncoder, UserDetailsService userDetailsService, AuthenticationManager authenticationManager, DataSource dataSource) {
        this.passwordEncoder = passwordEncoder;
        this.userDetailsService = userDetailsService;
        this.authenticationManager = authenticationManager;
        this.dataSource = dataSource;
    }


    @Bean
    public ClientDetailsService clientDetails() {
        JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
        // 使用哪一种加密方式
        clientDetailsService.setPasswordEncoder(passwordEncoder);
        return clientDetailsService;
    }

    // 用来配置授权服务器可以为哪些客户端授权   client_id,secret  redirect_url
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetails());// 使用jdbc存储
    }


    @Bean
    public TokenStore tokenStore() {
        JdbcTokenStore jdbcTokenStore = new JdbcTokenStore(dataSource);
        return jdbcTokenStore;
    }


    // 配置令牌存储

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
       endpoints.authenticationManager(authenticationManager);
       endpoints.tokenStore(tokenStore());// 配置令牌存储为数据库存储
        endpoints.userDetailsService(userDetailsService);

        // 配置 tokenServices 参数
        DefaultTokenServices tokenServices = new DefaultTokenServices();//修改默认令牌生成服务
        tokenServices.setTokenStore(endpoints.getTokenStore());// 基于数据库令牌生成
        tokenServices.setSupportRefreshToken(true);//是否支持刷新令牌
        tokenServices.setReuseRefreshToken(true); // 是否重复使用刷新令牌( 直到过期


        tokenServices.setClientDetailsService(endpoints.getClientDetailsService());//设置客户端信息
        tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());//用来控制令牌存储增强策略
        // 访问令牌的默认有效期( 以秒为单位)。过期的令牌为零或负数。
        tokenServices.setAccessTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(30)); // 30天

        endpoints.tokenServices(tokenServices);// 使用配置令牌服务

    }

}

1.3 security 配置

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {


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


    @Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();

        inMemoryUserDetailsManager.createUser(User.withUsername("root").password(passwordEncoder().encode("123456")).roles("ADMIN").build());
        return inMemoryUserDetailsManager;
    }


    @Override
    @Bean
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()// 开启表单登录
                .and()
                .csrf().disable();
    }
}

1.4 数据库配置

@Configuration
@Slf4j
public class MysqlDsConfig {

    /**
     *  配置数据源
     * @return
     */
    @Primary
    @Bean
    public DataSource mysqlDataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/oauth3");
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUsername("root");
        dataSource.setPassword("12345678");
        return dataSource;
    }

}

1.5 启动测试

当我们刷新token的时候 oauth_refresh_token 会有值进去,使用 apifox 测试令牌


二、资源服务器基于 jdbc 方式

需要连接数据库信息,跟认证服务器数据源一样,因为资源服务器最终也要去读取表信息

所需的依赖,资料参考 哔哩博主,不良人编程 

<properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
    </properties>


    <dependencies>
        <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.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-resource-server</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>

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

        <!-- 数据源支持 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.8</version>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>

    </dependencyManagement>

2.1  资源服务器配置

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {


    private final DataSource dataSource;

    @Autowired
    public ResourceServerConfig(DataSource dataSource) {
        this.dataSource = dataSource;
    }


    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.tokenStore(tokenStore());
    }


    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }
}

2.2 测试controller

@RestController
public class HelloController {



    @RequestMapping("hello")
    public String hello() {
        System.out.println("hello resource server ");

        return "hello resource server";
    }
}

2.3 测试结果

当我们这个时候访问的时候就需要带上 Authorization:Bearer   参数,否则提示 Full authentication is required to access this resource 

curl -H "Authorization:Bearer token 对应的值" http://127.0.0.1:8083/hello


三、认证服务器基于 jwt 方式

jwt 分为三部分,用三个点隔开  ,第一部分标识 header 标识用那种加密方式;中间部分为subject 主体信息,可以是用户信息,也可以是一个json数据;最后一部分为sign 签名信息,这个信息需要设置足够复杂才能被破解;

3.1 认证服务器配置

可能在疑问,为什么还是要用数据库,这次我们只需要从库里面读取一次用户信息,只是使用一张表 oauth_client_details 其他信息都不会使用,jwt 有自动过期时间

@Configuration
@EnableAuthorizationServer  //指定当前应用为授权服务器
public class JwtAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {


    private final PasswordEncoder passwordEncoder;
    private final UserDetailsService userDetailsService;
    private final AuthenticationManager authenticationManager;

    private final DataSource dataSource;

    @Autowired
    public JwtAuthorizationServerConfig(PasswordEncoder passwordEncoder, UserDetailsService userDetailsService, AuthenticationManager authenticationManager, DataSource dataSource) {
        this.passwordEncoder = passwordEncoder;
        this.userDetailsService = userDetailsService;
        this.authenticationManager = authenticationManager;
        this.dataSource = dataSource;
    }


    @Bean
    public ClientDetailsService clientDetails() {
        JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
        // 使用哪一种加密方式
        clientDetailsService.setPasswordEncoder(passwordEncoder);
        return clientDetailsService;
    }

    // 用来配置授权服务器可以为哪些客户端授权   client_id,secret  redirect_url
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetails());// 使用jdbc存储
    }



    // 使用同一个秘钥编码
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigningKey("12332111");
        return jwtAccessTokenConverter;
    }


    // jwt生成方式生成令牌
    @Bean
    public TokenStore tokenStore() {
        JwtTokenStore jdbcTokenStore = new JwtTokenStore(jwtAccessTokenConverter());
        return jdbcTokenStore;
    }


    // 配置令牌存储

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
       endpoints.authenticationManager(authenticationManager);
       endpoints.tokenStore(tokenStore())// 配置jwt令牌存储为数据库存储
         .accessTokenConverter(jwtAccessTokenConverter());
    }


    //http://127.0.0.1:8082/oauth/authorize?client_id=client&response_type=code&redirect_url=https://www.baidu.com

}

3.2 测试效果

1、页面授权效果有所不同,获取code

2、返回的令牌有所不同

api fox 效果

四、资源服务器基于 jwt 方式

    我们只需要跟认证服务器加密规则设置相同即可,因为jwt 自带加密算法,就类似于我们两个定义了一套rsa的秘钥,我们加密规则相同,约定一个签名戳,这个别人获取不到,你请求过来的时候我验证合法性,所以就不需要用到数据库了

4.1 资源服务器配置

@Configuration
@EnableResourceServer
public class JwtResourceServerConfig extends ResourceServerConfigurerAdapter {


    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.tokenStore(tokenStore());
    }

    // jwt生成方式生成令牌
    @Bean
    public TokenStore tokenStore() {
        JwtTokenStore jdbcTokenStore = new JwtTokenStore(jwtAccessTokenConverter());
        return jdbcTokenStore;
    }


    // 使用同一个秘钥编码
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigningKey("12332111");
        return jwtAccessTokenConverter;
    }
}

4.2 测试效果

curl -H "Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjYzMTY1MTAsInVzZXJfbmFtZ
SI6InJvb3QiLCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6IjEyYTgyMmNhLWQ3MTgtNDE1Yy1hYWQ3LTA5ZjIxODNjNzY0YiIsImNsaWVudF9pZCI6ImNsaWVudC1scSIsInNjb3BlI
jpbInJlYWQ6dXNlciJdfQ.myzFE0VJOhlFLOsddBknOeB6Y499RwZ1X2zTM4PxC00" http://127.0.0.1:8083/hello
 

Z1X2zTM4PxC00" http://127.0.0.1:8083/hello
hello resource server
D:\java-tool\idea-project\spring-security-study>
 

使用apifox 测试

Spring Boot Security是一个非常流行的安全框架,可以帮助开发人员实现各种安全功能。其中,OAuth2和JWT是两个非常重要的安全技术,可以用于实现授权和认证。下面是一个基于Spring Boot Security的完整示例,演示如何使用OAuth2和JWT实现安全功能。 1. 创建一个Spring Boot项目 使用Spring Initializr创建一个新的Spring Boot项目,添加以下依赖: - Spring Web - Spring Security - Spring Data JPA - H2 Database - Spring Security OAuth2 - jjwt 2. 添加配置文件 在application.properties文件中添加以下配置: ``` spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.jpa.hibernate.ddl-auto=create-drop spring.h2.console.enabled=true spring.h2.console.path=/h2-console spring.security.oauth2.client.registration.myapp.client-id=myapp spring.security.oauth2.client.registration.myapp.client-secret=myappsecret spring.security.oauth2.client.registration.myapp.scope=read,write spring.security.oauth2.client.provider.myapp.authorization-uri=http://localhost:8080/oauth/authorize spring.security.oauth2.client.provider.myapp.token-uri=http://localhost:8080/oauth/token spring.security.oauth2.client.provider.myapp.user-info-uri=http://localhost:8080/userinfo spring.security.oauth2.client.provider.myapp.user-name-attribute=name ``` 这些配置将用于配置数据源、Hibernate、H2控制台和OAuth2。 3. 创建实体类和仓库 创建一个User实体类,用于表示用户信息: ```java @Entity @Table(name = "user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false, unique = true) private String username; @Column(nullable = false) private String password; @Column(nullable = false) private String email; // getters and setters } ``` 创建一个UserRepository接口,用于操作User实体类: ```java @Repository public interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByUsername(String username); } ``` 4. 创建用户服务 创建一个UserService接口,用于定义获取用户和创建用户的方法: ```java public interface UserService { User createUser(String username, String password, String email); Optional<User> getUserByUsername(String username); } ``` 创建一个UserServiceImpl实现UserService接口,用于实现上述方法: ```java @Service public class UserServiceImpl implements UserService { @Autowired private UserRepository userRepository; @Autowired private PasswordEncoder passwordEncoder; @Override public User createUser(String username, String password, String email) { User user = new User(); user.setUsername(username); user.setPassword(passwordEncoder.encode(password)); user.setEmail(email); return userRepository.save(user); } @Override public Optional<User> getUserByUsername(String username) { return userRepository.findByUsername(username); } } ``` 5. 配置Spring Security 创建一个WebSecurityConfig类,用于配置Spring Security: ```java @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserService userService; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/oauth/**").permitAll() .anyRequest().authenticated() .and() .csrf().disable() .formLogin().disable() .httpBasic().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(username -> userService.getUserByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("User not found: " + username))) .passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } ``` 这个配置类将所有请求都需要进行认证,但是允许OAuth2请求。同时,禁用了CSRF、表单登录、HTTP基本认证和会话管理。 6. 配置OAuth2 创建一个OAuth2Config类,用于配置OAuth2: ```java @Configuration @EnableAuthorizationServer public class OAuth2Config extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserService userService; @Autowired private PasswordEncoder passwordEncoder; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("myapp") .secret(passwordEncoder.encode("myappsecret")) .authorizedGrantTypes("authorization_code", "refresh_token") .scopes("read", "write") .redirectUris("http://localhost:8081/login/oauth2/code/myapp"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager) .userDetailsService(username -> userService.getUserByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("User not found: " + username))) .accessTokenConverter(accessTokenConverter()) .pathMapping("/oauth/token", "/signin"); } @Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey("secret"); return converter; } @Bean public TokenStore tokenStore() { return new JwtTokenStore(accessTokenConverter()); } } ``` 这个配置类定义了一个OAuth2客户端,将授权码和刷新令牌作为授权类型,并允许读取和写入作用域。同时,定义了一个端点配置,将认证管理器、用户详情服务、访问令牌转换器和令牌存储配置到端点上。 7. 创建控制器 创建一个UserController类,用于处理用户相关的请求: ```java @RestController @RequestMapping("/users") public class UserController { @Autowired private UserService userService; @PostMapping public User createUser(@RequestBody UserDto userDto) { return userService.createUser(userDto.getUsername(), userDto.getPassword(), userDto.getEmail()); } @GetMapping("/{username}") public User getUser(@PathVariable String username) { return userService.getUserByUsername(username) .orElseThrow(() -> new NotFoundException("User not found: " + username)); } } ``` 这个控制器中定义了创建用户和获取用户的方法。 8. 创建JWT过滤器 创建一个JwtFilter类,用于在请求中验证JWT令牌: ```java public class JwtFilter extends OncePerRequestFilter { private static final String AUTHORIZATION_HEADER = "Authorization"; @Autowired private JwtAccessTokenConverter accessTokenConverter; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String authorizationHeader = request.getHeader(AUTHORIZATION_HEADER); if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { String token = authorizationHeader.substring(7); Authentication authentication = accessTokenConverter.extractAuthentication(token); SecurityContextHolder.getContext().setAuthentication(authentication); } filterChain.doFilter(request, response); } } ``` 这个过滤器会从请求头中获取JWT令牌,并使用令牌转换器验证令牌。如果验证通过,则将用户认证信息存储到Spring Security上下文中。 9. 注册JWT过滤器 在WebSecurityConfig类中,添加以下配置: ```java @Bean public JwtFilter jwtFilter() { return new JwtFilter(); } @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class); // ... } ``` 这个配置将JwtFilter注册到Spring Security过滤器链中。 10. 创建JWT工具类 创建一个JwtUtils类,用于生成和解析JWT令牌: ```java public class JwtUtils { public static final String SUBJECT = "myapp"; public static String generateToken(User user) { Map<String, Object> claims = new HashMap<>(); claims.put("sub", SUBJECT); claims.put("id", user.getId()); claims.put("username", user.getUsername()); claims.put("email", user.getEmail()); Date now = new Date(); Date expiration = new Date(now.getTime() + 60 * 60 * 1000); return Jwts.builder() .setClaims(claims) .setIssuedAt(now) .setExpiration(expiration) .signWith(SignatureAlgorithm.HS256, "secret") .compact(); } public static Long getUserIdFromToken(String token) { Claims claims = Jwts.parser() .setSigningKey("secret") .parseClaimsJws(token) .getBody(); return claims.get("id", Long.class); } } ``` 这个工具类将用户信息存储到JWT令牌中,并使用HS256算法进行签名。 11. 创建DTO类 创建一个UserDto类,用于接收创建用户的请求: ```java public class UserDto { private String username; private String password; private String email; // getters and setters } ``` 12. 测试 启动应用程序,并使用以下命令创建一个用户: ``` curl -X POST -H 'Content-Type: application/json' -d '{"username":"test","password":"test123","email":"test@example.com"}' http://localhost:8080/users ``` 使用以下命令获取访问令牌: ``` curl -X POST -vu myapp:myappsecret http://localhost:8080/oauth/token -H 'Accept: application/json' -d 'grant_type=authorization_code&code={CODE}&redirect_uri=http://localhost:8081/login/oauth2/code/myapp' ``` 将{CODE}替换为授权码,并将返回的访问令牌用于获取用户信息: ``` curl -H 'Authorization: Bearer {ACCESS_TOKEN}' http://localhost:8080/users/test ``` 将{ACCESS_TOKEN}替换为访问令牌,在请求头中发送即可。 以上就是一个完整的Spring Boot Security OAuth2 JWT示例,演示了如何实现授权和认证。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星空寻流年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值