(第二篇)微服务架构下无状态权限认证系统设计(Spring Security + Oauth2 + JWT)-- 实现

本文介绍了如何在微服务架构中设计无状态权限认证系统,利用Spring Security、Oauth2和JWT技术。文章详细阐述了授权中心的核心配置,包括web安全配置、用户服务实现等。接着讨论了网关的角色,如JWT解密、资源服务配置、自定义过滤器和权限验证。最后,作者提到该方案为个人经验总结,欢迎交流指正。
摘要由CSDN通过智能技术生成

一、参数配置

1)配置参数:application.yml
springcloud:
  security:
    oauth2:
      clients[0]:
        clientId: zuul-server
        clientSecret: '12345678'
        accessTokenValiditySeconds: 7200  //通行token有效时间(秒)
        refreshTokenValiditySeconds: 604800  //刷新token有效时间(秒)
      clients[1]:
        clientId: user-server
        clientSecret: '123456'
        accessTokenValiditySeconds: 7200
        refreshTokenValiditySeconds: 604800


2)单个客户端配置封装类:OAuth2ClientProperties.java
@Getter @Setter public class OAuth2ClientProperties { 
    private String clientId; //客户端id
    private String clientSecret; //客户端秘钥
    private Integer accessTokenValiditySeconds;  //通行token有效时长
    private Integer refreshTokenValiditySeconds; //刷新token有效时长
}

3)从配置文件获取配置封装到配置集合中:OAuth2Properties.java
@ConfigurationProperties(prefix = "springcloud.security.oauth2") //匹配前缀为springcloud.security.oauth2的参数
public class OAuth2Properties
{
    private OAuth2ClientProperties[] clients = {};//把参数放到数组中,此处也可以从数据库获取,本例子直接配置获取
    public OAuth2ClientProperties[] getClients() {
        return clients;
    }

    //OAuth2ClientProperties 单个配置实体封装
    public void setClients(OAuth2ClientProperties[] clients) {
        this.clients = clients;
    }
}

4)核心配置--扫描、注册自定义配置参数

@Configuration
@EnableConfigurationProperties(OAuth2Properties.class)
public class OAuth2CoreConfig
{
}
二、业务配置
1)认证授权参数配置
@Configuration
@EnableResourceServer
@EnableAuthorizationServer  //开启授权服务
public class OAuth2Config1 extends AuthorizationServerConfigurerAdapter
{
    private JsonParser objectMapper = JsonParserFactory.create();
    
    @Autowired
    private AuthenticationManager authenticationManager;
    
    @Autowired
    private OAuth2Properties oauth2Properties;//注入配置类
    
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        //这句不知道是干啥的,大概是开启一个身份验证表单的功能吧,就是弹出一个输入账户、密码的框
        oauthServer.allowFormAuthenticationForClients();
    }
    
    /*配置客户端基本信息,循环配置数组,加载到配置服务运行内存,用于授权判断*/
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 客户端配置化
        InMemoryClientDetailsServiceBuilder build = clients.inMemory();
        if (ArrayUtils.isNotEmpty(oauth2Properties.getClients())) {
            // 验证模式:刷新token,密码、验证码模式,也可根据客户端自定义配置
            for (OAuth2ClientProperties config : oauth2Properties.getClients()) {
                build.withClient(config.getClientId()).secret(config.getClientSecret())
                    .accessTokenValiditySeconds(config.getAccessTokenValiditySeconds())   //通行token
                    .refreshTokenValiditySeconds(config.getRefreshTokenValiditySeconds()) // 刷新token
                    .authorizedGrantTypes("refresh_token", "password", "authorization_code")//验证模式
                    .scopes("platform");//作用域,可以在配置中按实际业务自定义各个客户端的作用域,写死并不可取
            }
        }
    }
    
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        //JWT方式
        endpoints.tokenStore(tokenStore())//设置token存储方式,见方法实现
        .tokenEnhancer(jwtTokenEnhancer()) //设置token的加密方式,见方法实现
        .authenticationManager(authenticationManager);//开启密码类型验证的bean
    }
    
    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(jwtTokenEnhancer());
    }
    
    /*JWT token生成规则,此处对原来的转换器 JwtAccessTokenConverter 下的方法 enhance() 进行重写,
      来补充生成token中自定义的业务字段,如组织架构id、用户id等字段*/
    @Bean
    public JwtAccessTokenConverter jwtTokenEnhancer() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter() {

            /*重写token生成方法,补充组织架构、用户id内容*/
            @Override
            public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
                DefaultOAuth2AccessToken result = new DefaultOAuth2AccessToken(accessToken);
                Map<String, Object> info = new LinkedHashMap<String, Object>(accessToken.getAdditionalInformation());//附加信息map
                String tokenId = result.getValue();
                if (!info.containsKey(TOKEN_ID)) {
                    info.put(TOKEN_ID, tokenId);
                }
                else {
                    tokenId = (String) info.get(TOKEN_ID);
                }

                //自定义信息设置到token负载中
                SysUser user = (SysUser)authentication.getPrincipal();//SysUser:系统的登录用户实体,根据实际业务设计
                info.put("orgId", us
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值