【Spring Boot 集成应用】 OAUTH2集成配置案例(JWT+Redis+增强TOKEN方式)

阅读: 评论:0

【Spring Boot 集成应用】 OAUTH2集成配置案例(JWT+Redis+增强TOKEN方式)

【Spring Boot 集成应用】 OAUTH2集成配置案例(JWT+Redis+增强TOKEN方式)

1. 工程搭建
  1. 创建工程spring-boot-security-oauth2

  2. 启动类

    com.mirson.spring.boot.security.oauth.startup.SecurityOauthApplication

    @SpringBootApplication
    @ComponentScan(basePackages = {"com.mirson"})
    @EnableCaching
    public class SecurityOauthApplication {public static void main(String[] args) {SpringApplication.run(SecurityOauthApplication.class, args);}}

    指定扫描路径, 开启缓存注解。

  3. MAVEN依赖

    POM.XML

    <dependencies><!-- Spring Boot Security 安全依赖组件 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- Spring Boot Oauth2 认证组件 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId><version>2.1.1.RELEASE</version></dependency><!-- Spring Boot Web 依赖组件 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Boot 自动化缓存依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency><!--Spring Boot Data Redis 缓存依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- Apache Commons 工具依赖 --><dependency><groupId>org.apachemons</groupId><artifactId>commons-lang3</artifactId></dependency></dependencies>

    这里的依赖采用spring-cloud的OAUTH2封装来实现的自动化配置, 与spring-boot-starter-oauth2依赖实质是一样, 都是基于Spring-Security封装, 属性配置基本一致, 如果要加入Spring Cloud, 可以直接集成使用。

2. 创建用户对象

定义两个用户对象, 一个是OAUTH的用户认证对象, 一个是我们接口测试的用户对象。

  • OAUTH用户认证对象

    com.mirson.spring.boot.security.oauth.po.OAuthUser

    @Data
    public class OAuthUser extends User {/*** 用户ID标识*/private Integer id;/*** 创建日期*/private Date createTime;public OAuthUser(String account, String password){super(account, password, true, true, true, true, Collections.EMPTY_SET);this.id = Int(0, 100);ateTime = new Date();}}
    
  • 接口测试用户对象

    com.mirson.spring.boot.security.oauth.po.User

    @Data
    public class User {/*** ID*/private Integer id;/*** 用户名称*/private String name;/*** 年龄*/private String age;/*** 省份*/private String province;/*** 创建时间*/private Date createDate;}
3. 提供资源接口

定义一个获取用户信息的接口, 受资源权限保护。

com.mirson.spring.boot.ller.UserController

@RestController
@RequestMapping("/user")
@Log4j2
public class UserController {@RequestMapping("/getUserInfo")@ResponseBodypublic User getUserInfo() {User user = new User();user.setId(0);user.setAge("21");user.setName("user1");user.setCreateDate(new Date());return user;}}
4. OAUTH2集成与权限配置
  1. 工程配置

    # 服务端口
    server:port: 22619
    # 服务名称  
    spring:application:name: security-oauth2

    这里我们便于测试, 我们将认证服务和资源服务放置一起,以上配置即可, 不需加任何其他配置。

    如果资源服务是独立的, 工程配置需要加入以下信息:

    ## spring security 配置
    security:oauth2:resource:jwt:# JWT 密钥信息key-value: sign_secret# TOKEN验证接口地址  token-info-uri: 127.0.0.1:21619/oauth/check_tokenclient:# 客户端模式配置client-id: democlient-secret: 123456scope: serveraccess-token-uri: 127.0.0.1:21619/oauth/tokenuser-authorization-uri: 127.0.0.1:21619/oauth/authorize
    
  2. 认证服务配置

    新建com.mirson.spring.boot.fig.AuthorizationServerConfig配置类, 加入以下配置:

    • Redis 配置

       /*** Redis 缓存配置
      * @return*/@Beanpublic RedisTemplate<String, Object> stockRedisTemplate() {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());redisTemplate.setConnectionFactory(redisConnectionFactory);return redisTemplate;}
      

      设置redis的key, value 序列化方式。

    • 采用Redis存储TOKEN信息

        /*** TokenStore实现方式, 采用Redis缓存* @return*/@Beanpublic TokenStore redisTokenStore() {RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);tokenStore.setPrefix(OAUTH_PREFIX_KEY);tokenStore.setAuthenticationKeyGenerator(new DefaultAuthenticationKeyGenerator() {@Overridepublic String extractKey(OAuth2Authentication authentication) {actKey(authentication);}});return tokenStore;}
      

      统一Redis的Key前缀, 便于维护。

    • 结合Token增强技术

          /*** token增强处理, 支持扩展信息* @return TokenEnhancer*/@Beanpublic TokenEnhancer tokenEnhancer() {return (accessToken, authentication) -> {try {if (OAUTH_CLIENT_CREDENTIALS.OAuth2Request().getGrantType())) {return accessToken;}final Map<String, Object> additionalInfo = new HashMap<>(16);OAuthUser authUser = (OAuthUser) UserAuthentication().getPrincipal();if (null != authUser) {// 放入扩展信息additionalInfo.put("oauth_user_id", Id());additionalInfo.put("oauth_user_date", CreateTime());additionalInfo.put("active", true);}((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);}catch(Exception e) {(e.getMessage(), e);}return accessToken;};}
      

      TOKEN增强可以放置额外信息,扩展性强, 更为灵活, 这些信息不会加入JWT中。

    • JWT TOKEN配置

          /*** JWT TOKEN配置,采用签名密钥*/@Beanpublic JwtAccessTokenConverter accessTokenConverter() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey(OAUTH_SIGN_KEY);return converter;}
      

      JWT可以支持密钥签名, 还可以通过证书签名方式, 安全性比较高。

    • 采用内存模式对客户端进行验证

      @Overridepublic void configure(ClientDetailsServiceConfigurer clients)throws Exception {clients.inMemory().withClient("demo").secret("4QrcOUm6Wau+VuBX8g+IPg==").authorizedGrantTypes("password", "authorization_code");}
      

      原始密码为123456, 我们采用了密码编码器, 这里的密码要设置为密文。

    • 认证服务配置

        /*** 认证服务配置* @param endpoints*/@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) {// 自定义token生成方式TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST).tokenStore(redisTokenStore()).tokenEnhancer(tokenEnhancerChain).userDetailsService(authCustomUserDetailService).authenticationManager(authenticationManager).reuseRefreshTokens(false);}

      采用Token链, 申请TOKEN的时候, 不仅返回JWT信息, 还返回TOKEN 增强设置的信息。

  3. 自定义密码编码器

    com.mirson.spring.boot.fig.AuthPasswordEncoder

    /*** 自定义密码加密方式*/
    @Component
    @Log4j2
    public class AuthPasswordEncoder implements PasswordEncoder {/*** 编码处理* @param rawPassword* @return*/@Overridepublic String encode(CharSequence rawPassword) {String();}/*** 密码校验判断* @param rawPassword* @param encodedPassword* @return*/@Overridepublic boolean matches(CharSequence rawPassword, String encodedPassword) {if(rawPassword != null && rawPassword.length() > 0){try {// 这里通过MD5及B64加密String password = String());boolean isMatch= encodedPassword.equals(password);if(!isMatch) {log.warn(" password not match!");}return encodedPassword.equals(password);} catch (Exception e) {(e.getMessage(), e);}}return false;}}

    可以自定义编码, 比如BASE64等, 自定义校验逻辑,能够灵活处理。

  4. 认证服务WEB配置

    com.mirson.spring.boot.fig.WebSecurityConfiguration

    /*** 认证相关配置*/
    @Primary
    @Order(90)
    @Configuration
    public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService authCustomClientDetailService;@Autowiredprivate AuthPasswordEncoder authPasswordEncoder;@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/user/getUserInfo").authenticated().anyRequest().permitAll().and().csrf().disable()                // 禁用csrf保护(防止伪造攻击).httpBasic().disable();   // 禁用弹出式认证框}@Bean@Override@SneakyThrowspublic AuthenticationManager authenticationManagerBean() {return super.authenticationManagerBean();}@Autowired@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(authCustomClientDetailService).passwordEncoder(authPasswordEncoder);}}

    主要看configure方法配置, 设置哪些需要鉴权的接口地址, 禁用csrf保护, 防止无法请求的情况, 禁用弹出式认证框, 防止调用资源接口时出现401错误。

  5. 自定义用户服务接口

    com.mirson.spring.boot.fig.AuthCustomUserDetailService

    @Service("authCustomUserDetailService")
    public class AuthCustomUserDetailService implements UserDetailsService {@Autowiredprivate CacheManager cacheManager;@Overridepublic UserDetails loadUserByUsername(String userNo) throws UsernameNotFoundException {// 查询缓存Cache cache = Cache(AuthorizationServerConfig.OAUTH_KEY_USER_DETAILS);if (cache != null && (userNo) != null) {return (UserDetails) (userNo).get();}// 封装成OAUTH鉴权的用户对象UserDetails userDetails = new OAuthUser("admin", "AZICOnu9cyUFFvBp3xi1AA==");// 将用户信息放入缓存cache.put(userNo, userDetails);return userDetails;}
    }

    这里加入了缓存处理, 实际项目当中, 也推荐使用缓存, 提升处理性能。

    如果缓存没有用户, 会构造一个新的用户放入缓存, 密码要采用密文。

  6. 资源服务配置

    如果有提供受保护的资源服务, 必须要做具体的配置。

    新建com.mirson.spring.boot.fig.ResourceServerConfiguration

    /*** 自定义资源服务器配置*/
    @EnableResourceServer
    @Configuration
    public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {@Overridepublic void configure(HttpSecurity http) throws Exception {http.antMatcher("/user/getUserInfo").authorizeRequests().anyRequest().authenticated();}
    }
    

    设置了一个受保护的资源接口/user/getUserInfo, 其他接口全部放行。

5. 功能验证
  1. 申请TOKEN,获取JWT与TOKEN增强信息

    • 设置Basic Auth认证信息


    这里填入的是客户端模式的用户名和密码,并非认证用户信息。

    • 设置密码模式的请求参数信息

    • 请求返回结果

      可以看到JWT的TOKEN信息, 以及增强设置中的ID和DATE信息。

  2. 访问受保护的资源接口

    • 请求获取用户信息接口, 如果不传入TOKEN, 会提示无权访问

    • 传入TOKEN访问

      能够正常访问接口, 注意, 传入的TOKEN要选择【Bearer Token】方式。

  3. 访问TOKEN信息

    请求接口, 传入token参数: 127.0.0.1:22619/oauth/check_token

    可以看到JWT TOKEN的详细信息。

6. 总结
  • 掌握Spring Boot 与Spring Security 和OATUH2的集成用法, 在微服务场景当中,也能够适用, 微服务应用中一般会接入网关进行统一鉴权,也可以由各资源服务再做鉴权处理 ,方式灵活多样。
  • 这里用到了OAUTH2的客户端模式和密码模式, 适合微服务场景大用户量的接入,采用Redis缓存, 能够保障较高的性能, JWT附带信息不能过多, 会增加传输资源开销, 加密方式也不能过于复杂, 影响CPU性能, 如果有较多额外信息需要传递, 可以采用TOKEN增强模式, 数据存储在缓存, 不会带来过多的IO开销。在实际项目当中, 要做仔细权衡,能加入缓存地方尽量加入, 保障安全的同时, 也要有较好的性能。

源码下载地址:

本文发布于:2024-01-29 05:20:38,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170647684412983.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:案例   方式   Boot   Spring   Redis
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23