Oauth2.0+JWT

1.OAuth2.0概念

OAuth 2.0 是一种授权框架,允许第三方应用在用户的批准下访问其存储在另一服务提供方上的受保护资源,而无需直接暴露用户的凭证。

客户端:本身不存储资源,需要通过资源拥有者去请求资源服务器的资源。

资源拥有者:通常可以理解为用户

授权服务器:用于对资源拥有者的身份进行认证,对访问资源进行授权。客户端如果想要访问资源的话需要 资源拥有者 通过向 授权服务器 授权后才可以访问

资源服务器:存储资源的服务器,客户端最终需要通过资源服务器来获取资源。

2.授权模式
2.1 授权码(Authorization Code)模式 *

这是最常见的模式,适用于服务器端的应用程序。
流程包括:
        客户端引导用户到授权服务器请求授权;
        用户同意后,授权服务器返回一个授权码给客户端;
        客户端使用授权码与授权服务器交换访问令牌(access token);
        客户端持有访问令牌访问资源服务器。


2.2 简化授权(Implicit)模式

在用户授权之后,授权服务器直接将访问令牌返回给客户端(通常是在重定向URI的hash fragment中);
因为没有涉及到授权码交换的过程,所以这种模式相对简单,但存在安全隐患,不适合敏感资源的授权。

2.3 密码(Resource Owner Password Credentials)模式 *

在用户对客户端高度信任的情况下使用,例如企业内部应用。
客户端直接接收用户提供的用户名和密码,并使用这些凭证向授权服务器请求访问令牌;
这种模式安全性较低,因为它要求用户将密码提供给第三方应用,违反了最小权限原则。

2.4 客户端凭证(Client Credentials)模式

用于客户端自身的授权,而非用户的授权。
客户端使用自己的凭证向授权服务器请求访问令牌;
在这种模式下,客户端代表自己而不是用户去获取对受保护资源的访问权;
主要应用于机器对机器通信,或者不需要用户干预的后台服务之间的交互。

3. 引入依赖
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
4. 架构实现步骤

开启单点登录:@EnableOAuth2Sso

@SpringBootApplication
//用于开启SpringSecurity提供的隐藏注解
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
//开启单点登录
@EnableOAuth2Sso
public class OauthDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(OauthDemoApplication.class, args);
    }

}
4.1授权码模式(authorization_code)

(1)自定义登录逻辑

@Service
public class UserSecurityServiceImpl implements UserDetailsService {
    @Autowired
    private PasswordEncoder pe;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //1.查询数据库,获取用户名和密码
        User u=userMapper.findUser(username);
        //2。拿密码(密文)进行解析
        String password=pe.encode(u.getPassword);
        //返回的User和上面的User不是一个类,此处返回的User为SpringSecurity中的,AuthorityUtils.commaSeparatedStringToAuthorityList用于生成权限
        return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal,ROLE_A"));
        //admin和normal为权限,而ROLE_XXX为角色
    }
}

(2)配置SpringSecurityConfig

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public PasswordEncoder getPasswordEncode(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                //允许以下url的访问
                .authorizeRequests()
                .antMatchers("/oauth/**","/login/**","/logout")
                .permitAll()
                //剩余的都需要认证才可以访问
                .anyRequest()
                .authenticated()
                .and()
                //表单的访问,配置都为默认值
                .formLogin()
                .permitAll();
    }
}

(3)配置授权服务器

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                //配置client-id
                .withClient("admin")
                //配置client-secret
                .secret(passwordEncoder.encode("123456"))
                //有效期
                .accessTokenValiditySeconds(3600)
                //授权后跳转连接
                .redirectUris("http://www.baidu.com")
                //配置申请权限范围
                .scopes("all")
                //配置grant_type 授权类型
                .authorizedGrantTypes("authorization_code");
    }
}

(4)配置资源服务器

@Configuration
@EnableResourceServer
public class ResourceServerConnfig extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .requestMatchers()
                 //需要被获取的资源链接都需要在此处放行
                .antMatchers("/user/**");
    }
}

(5)通过链接跳转至登录页获取授权码

例:https://example.com/oauth/authorize?response_type=code&client_id=your_client_id&redirect_uri=https%3A%2F%2Fclient.example.com%2Fcallback&scope=read write

请求URL包含以下参数:

response_type: 必须设置为code,表明请求的是授权码。

client_id: 客户端在授权服务器注册时获得的ID。

redirect_uri: 客户端预先注册的重定向URI,授权服务器会在授权完成后将用户代理重定向至此地址,并附带授权码。

scope: 请求的权限范围,可选。

(6)使用获取到的验证码,通过/oauth/token获取到访问的token

4.2 密码模式(password)

(1)重写并注册AuthenticationManager

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public PasswordEncoder getPasswordEncode(){
        return new BCryptPasswordEncoder();
    }

    
    //重写并注册Bean :AuthenticationManager
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception{
        return super.authenticationManagerBean();
    }

     //......
}

(2)修改授权服务器配置(改为密码模式),并重写configure

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserSecurityServiceImpl userSecurityService;

    //使用密码模式所需配置authenticationManager和userSecurityService
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager).userDetailsService(userSecurityService);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                //配置client-id
                .withClient("admin")
                //配置client-secret
                .secret(passwordEncoder.encode("123456"))
                //有效期
                .accessTokenValiditySeconds(3600)
                //授权后跳转连接
                .redirectUris("http://www.baidu.com")
                //配置申请权限范围
                .scopes("all")
                //配置grant_type 授权类型
                .authorizedGrantTypes("password");
    }
}

(3)使用用户名和密码通过oauth/token获取token,client_id和client_secret配置于Auth或Form中

4.3 客户端模式(client_credentials)

(1)修改授权服务器配置(改为客户端模式)

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserSecurityServiceImpl userSecurityService;

    //......

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                //配置client-id
                .withClient("admin")
                //配置client-secret
                .secret(passwordEncoder.encode("123456"))
                //有效期
                .accessTokenValiditySeconds(3600)
                //授权后跳转连接
                .redirectUris("http://www.baidu.com")
                //配置申请权限范围
                .scopes("all")
                //配置grant_type 授权类型
                .authorizedGrantTypes("password,client_credentials");
    }
}

(2)使用client_id和client_scret通过oauth/token获取token

5. redis存储token

(1)配置RedisConfig

@Configuration
public class RedisConfig {

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;
    @Bean
    public TokenStore tokenStore(){
        return new RedisTokenStore(redisConnectionFactory);
    }
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new JedisConnectionFactory();
    }
}

(2)配置认证服务器的tokenStore

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    //......
    @Autowired
    @Qualifier("tokenStore")
    private TokenStore tokenStore;

    //使用密码模式所需配置authenticationManager和userSecurityService
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager)
                .userDetailsService(userSecurityService)
                .tokenStore(tokenStore);
    }

    //......
}
6. JWT简介

        JWT,全称为JSON Web Token,是一种开放标准(RFC 7519),用于安全地在各方之间传输信息。JWT提供了一种紧凑且自包含的方法,以JSON对象的形式封装信息,这些信息可以被验证和信任,原因在于它被数字签名所保护。JWT主要应用于身份验证和授权场景中,但也可用于其他需要安全传输信息的场合。

JWT结构上分为三个部分:

头部(Header):包含JWT的元数据,如其类型(通常是JWT)和所采用的签名算法(如HS256、RS256等)。
载荷(Payload):包含JWT的实际信息或声明,可以是用户标识符、用户角色、过期时间等。这部分信息可以是不敏感的,因为它是可被解析的。
签名(Signature):通过将头部和载荷分别进行Base64编码后,使用头部中指定的算法和一个秘钥(或密钥对)对这两个编码后的字符串进行签名,确保JWT的完整性和来源的真实性。
JWT的工作流程通常如下:

用户通过认证后,服务器生成一个JWT并发送给用户。
用户在后续的每一次请求中,都将这个JWT附在HTTP请求头中发送给服务器。
服务器收到JWT后,使用相同的秘钥验证JWT的有效性(包括签名校验、过期时间检查等),从而确认用户的身份和权限,无需查询数据库或会话存储。
相比于传统的session认证,JWT减少了服务器存储负担,支持跨域认证,并且易于扩展,特别适合分布式系统和微服务架构。然而,也需要注意JWT的安全管理,例如保护好秘钥、不过度信任JWT内容、合理设置过期时间等。

7. Oauth2.0整合JWT

(1)配置JwtTokenStoreConfig

@Configuration
public class JwtTokenStoreConfig {

    @Bean(name = "jwt")
    public TokenStore JwtTokenStore(){
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter(){
        JwtAccessTokenConverter accessTokenConverter=new JwtAccessTokenConverter();
        //配置JWT使用的密钥
        accessTokenConverter.setSigningKey("test_key");
        return accessTokenConverter;
    }
}

(2)修改认证服务器配置

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    //......
    //1.主动注入配置
    @Autowired
    @Qualifier("jwtTokenStore")
    private TokenStore tokenStore;
    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;


    //2.配置TokenStore和AccessTokenConverter
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager).userDetailsService(userSecurityService)
                .tokenStore(tokenStore)
                .accessTokenConverter(jwtAccessTokenConverter);
    }

    //......
}
8. 拓展JWT中存储的内容

(1)配置JwtTokenEnhancer

public class JwtTokenEnhancer implements TokenEnhancer {
    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) {
        Map<String,Object> info=new HashMap<>();
        //自定义扩展内容
        info.put("enhance","enhance info");
        ((DefaultOAuth2AccessToken)oAuth2AccessToken).setAdditionalInformation(info);
        return oAuth2AccessToken;
    }
}

(2)手动注册Bean:JwtTokenEnhancer

@Configuration
public class JwtTokenStoreConfig {

    //.....

    //手动注册Bean
    @Bean
    public JwtTokenEnhancer jwtTokenEnhancer(){
        return new JwtTokenEnhancer();
    }
}

(3)修改认证服务器配置

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    //......
    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;
    @Autowired
    private JwtTokenEnhancer jwtTokenEnhancer;


    //使用密码模式所需配置authenticationManager和userSecurityService
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        //配置JWT内容增强器
        TokenEnhancerChain enhancerChain=new TokenEnhancerChain();
        List<TokenEnhancer> delegates=new ArrayList<>();
        delegates.add(jwtTokenEnhancer);
        delegates.add(jwtAccessTokenConverter);
        enhancerChain.setTokenEnhancers(delegates);

        endpoints.authenticationManager(authenticationManager).userDetailsService(userSecurityService)
                .tokenStore(tokenStore)
                .accessTokenConverter(jwtAccessTokenConverter);
    }

    //......
}

备注:解析JWT的Token需要使用[  io.jsonwebtoken-jjwt  ]

9.  刷新令牌

只需在授权服务器中的授权类型添加 refresh_token即可

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    //......

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                //配置client-id
                .withClient("admin")
                //配置client-secret
                .secret(passwordEncoder.encode("123456"))
                //有效期
                .accessTokenValiditySeconds(3600)
                //授权后跳转连接
                .redirectUris("http://www.baidu.com")
                //配置申请权限范围
                .scopes("all")
                //配置grant_type 授权类型  及 *添加令牌刷新机制
                .authorizedGrantTypes("password","refresh_token");
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Spring Boot、OAuth2.0JWT Token鉴权认证开发的后台接口是一种使用现代化技术实现的身份验证和授权机制。下面是关于这种后台接口的一些说明: 首先,Spring Boot是一个基于Spring框架的快速开发框架,提供了简化的配置和自动化的特性,使开发者能够更快速高效地开发后台接口。 OAuth2.0是一种开放标准的授权协议,它允许用户授权第三方应用访问他们在资源拥有者上存储的信息,而不需要将用户名和密码提供给第三方。 JWT Token(JSON Web Token)是一种用于在网络应用间安全传递声明的一种方式。它被用作身份验证和授权的令牌,通过加密并以JSON格式存储信息,确保信息的完整性和安全性。 基于以上技术,我们可以开发出具有强大安全认证能力的后台接口。首先,用户在访问接口时,需要提供他们的身份证明,这可以是用户名和密码。接口服务器会使用OAuth2.0协议进行身份验证,并颁发JWT Token给用户。用户在未来的请求中,可以使用该Token进行身份验证,而无需每次都提供用户名和密码。 接口服务器会对JWT Token进行验证,以确保Token的完整性和有效性。如果Token失效或被伪造,访问将被拒绝。如果验证通过,接口服务器会正常处理用户的请求。 使用Spring Boot和OAuth2.0进行开发,可以方便地设置权限和角色。可以根据用户的角色和权限,限制他们对某些资源的访问。 总之,基于Spring Boot、OAuth2.0JWT Token鉴权认证开发的后台接口提供了一种安全可靠的身份验证和授权机制,能够有效保护后台接口的安全性,防止非法访问和数据泄露。这种技术组合在开发现代化的网络应用时非常有用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值