微服务09:单点登陆系统设计及实现2

Security 认证流程分析(了解)

目前的登陆操作,也就是用户的认证操作,其实现主要基于Spring Security框架,其认证简易流程:å¨è¿éæå¥å¾çæè¿°

颁发登陆成功令牌



构建令牌存储对象

本次我们借助JWT(Json Web Token-是一种json格式)方式将用户相关信息进行组织和加密,并作为响应令牌(Token),从服务端响应到客户端,客户端接收到这个JWT令牌之后,将其保存在客户端(例如localStorage),然后携带令牌访问资源服务器,资源服务器获取并解析令牌的合法性,基于解析结果判定是否允许用户访问资源.

//创建令牌存储的服务配置
@Configuration
public class TokenConfig {
    //为令牌设置一个口令,可以自定义设置
    //生成的密匙需要此口令进行签名,拿到的令牌需要此口令进行验证
    private String SIGNING_KEY= "auth";

    //创建令牌存储TokenStore 对象,内部存储的是一个访问令牌转换器jwtAccessTokenConverterjwt对象
    @Bean
    public TokenStore tokenStore(){
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    //构建JWT令牌转换器方法,基于此方法返回创建好的令牌,解析令牌
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter(){
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        //为创建 访问令牌转换器jwtAccessTokenConverter对象 设置签名的密钥
        jwtAccessTokenConverter.setSigningKey(SIGNING_KEY);
        //返回设置好的令牌
        return jwtAccessTokenConverter;
    }
}

定义认证授权核心配置

第一步:在SecurityConfig中添加如下方法(创建AuthenticationManager 身份验证管理器对象,后面授权服务器会用到):

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

第二步:配置认证和授权服务


/**
 * 在这个对象中负责将所有的认证和授权配进行整合,例如
 * 1)SpringSecurity (安全认证和授权)
 * 2)TokenConfig(提供了令牌的生成,储存,校验)
 * 3)Oauth2(定义了一套认证规范,例如给谁发令牌,发什么)
 */

//AuthorizationServerConfigurerAdapter 授权服务器配置器适配器
@Configuration
@AllArgsConstructor//构造全参函数方法
@EnableAuthorizationServer //开启认证和授权服务
public class Oauth2Config extends AuthorizationServerConfigurerAdapter{
    //负责完成认证管理
    private AuthenticationManager authenticationManager;
    //服务获取用户信息
    private UserDetailsService userDetailsService;
    //TokenStore负责完成令牌创建,信息读取
    private TokenStore tokenStore;
    //负责密码加密匹配对象
    private PasswordEncoder passwordEncoder;
    //JWT令牌转换器(基于用户信息构建令牌,解析令牌)
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    /**
     * 认证方式配置
     * @param endpoints
     * @throws Exception
     * */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        //super.configure(endpoints);
        //操作endpoints的相关属性
        //完成认证的对象
        endpoints.authenticationManager(authenticationManager);
        //访问数据库的对象。 认证需要两部分信息,一部分来自数据库,一部分来自客户端
        endpoints.userDetailsService(userDetailsService);
        //支持对什么请求进行认证? 默认只支持post方法,可以自行添加
        endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
        //认证成功以后令牌如何存储?默认令牌是UUID.randomUUID(),并且默认存在内存中
        endpoints.tokenServices(tokenServices());
    }


    //系统底层在完成认证以后会调用TokenServuce对象的相关方法
    //获取TokenStore,基于TokenStore获取token对象
    @Bean
    public AuthorizationServerTokenServices tokenServices(){
        //1.构建TokenService Token服务 对象(此对象提供了创建,获取,刷新token的方法)
        DefaultTokenServices tokenServices = new DefaultTokenServices();

        //2设置访问令牌过期了,是否支持通过令牌刷新机制延长有效时间,设置支持刷新令牌
        tokenServices.setSupportRefreshToken(true);

        //3.设置令牌生产和存贮策略
        tokenServices.setTokenStore(tokenStore);

        //4.设置令牌增强(允许设置令牌生成策略,默认令牌比较简单,没有事业务数据,
        // 就是简单的随机字符,现在希望使用jwt策略)
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(
                jwtAccessTokenConverter));
        tokenServices.setTokenEnhancer(tokenEnhancerChain);

        //设置访问令牌有效期时长,设置接入令牌有效期
        tokenServices.setAccessTokenValiditySeconds(3600);

        //设置“刷新令牌有效期”
        tokenServices.setRefreshTokenValiditySeconds(3600*72);
        //返回设置好的令牌服务
        return tokenServices;
    }

    /**
     * 假如入我们输入了用户名和密码,然后点提交,提交到哪呢?
     * 临牌过去了,重写生成一个令牌
     * 那个路径可以帮助我们重新生成?
     * 这个方法就可以提供这个配置
     * 对外提供认证,令牌刷新,校验等路径(url)
     * @param security
     * @throws Exception
     * */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        //super.configure(security);
        //设置security的属性,permitAll()是官方定义好的
        //1.定义认证的url,"permitAll()"表示所有的url
        security.tokenKeyAccess("permitAll()");
        //2.定义检查url
        security.checkTokenAccess("permitAll()");
        //3.允许直接认证,直接通过表单方式提交认证
        security.allowFormAuthenticationForClients();
    }

    /**
     * 认证中心需要给所有的用户端的用户发令牌吗?
     * 发令牌有一些规则的定义
     * 客户端详情配置
     * @param clients
     * @throws Exception
     * */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //super.configure(clients);
        clients.inMemory()
                //定义客户端的id(客户端提交认证时需要这个id)
                .withClient("gateway-client")
                //定义秘钥(客户端提交用户信息时需要携带这个秘钥)
                .secret(passwordEncoder.encode("123456"))
                //定义作用范围(所有符合规则的客户端)
                .scopes("all")
                //认证的模式(允许客户端基于密码方法,刷新令牌方式实现认证)
                .authorizedGrantTypes("password","refresh_token");
    }

}

配置网关认证的URL

  - id: router02
      uri: lb://sca-auth
      predicates:
        #- Path=/auth/login/**  #没要令牌之前,以前是这样配置
        - Path=/auth/oauth/**   #微服务架构下,需要令牌,现在要这样配置
      filters:
        - StripPrefix=1

Postman访问测试

第一步:启动服务
依次启动sca-auth服务,sca-resource-gateway服务。

第二步:检测sca-auth服务控制台的Endpoints信息,例如:

å¨è¿éæå¥å¾çæè¿°

 第三步:打开postman进行登陆访问测试

http://localhost:9000/auth/oauth/token?username=jack&password=123456&client_id=gateway-client&grant_type=password&client_secret=123456

å¨è¿éæå¥å¾çæè¿°

 登陆成功会在控制台显示令牌信息,例如:

{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MzI3NDEzODMsInVzZXJfbmFtZSI6ImphY2siLCJhdXRob3JpdGllcyI6WyJzeXM6cmVzOmNyZWF0ZSIsInN5czpyZXM6cmV0cmllY2UiXSwianRpIjoiZjQyMGViMGYtZDFjNi00YTc2LWIyY2ItY2QzMDU4OTU3MDk4IiwiY2xpZW50X2lkIjoiZ2F0ZXdheS1jbGllbnQiLCJzY29wZSI6WyJhbGwiXX0.xatqAhlJMCAgU_wZK3M4himRjQFHjYcTCWmdIQO5aSU",
    "token_type": "bearer",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJqYWNrIiwic2NvcGUiOlsiYWxsIl0sImF0aSI6ImY0MjBlYjBmLWQxYzYtNGE3Ni1iMmNiLWNkMzA1ODk1NzA5OCIsImV4cCI6MTYzMjk5Njk4MywiYXV0aG9yaXRpZXMiOlsic3lzOnJlczpjcmVhdGUiLCJzeXM6cmVzOnJldHJpZWNlIl0sImp0aSI6ImQ1MmFkMTE3LTAyMGYtNDM3OS1hNTcyLTQ3ZWRkZDJhODQwNCIsImNsaWVudF9pZCI6ImdhdGV3YXktY2xpZW50In0.Bw2pqzUWKeVErReRG2StYG-PI38r_n6orBhI-ZeNCdk",
    "expires_in": 3599,
    "scope": "all",
    "jti": "f420eb0f-d1c6-4a76-b2cb-cd3058957098"
}

登陆页面登陆方法设计

登陆成功以后,将token存储到localStorage中,修改登录页面的doLogin方法,例如

覆盖原来网页的diLogin()方法

  doLogin() {
    //1.定义url
     let url = "http://localhost:9000/auth/oauth/token"
    //2.定义参数
      let params = new URLSearchParams()
       params.append('username',this.username);
       params.append('password',this.password);
       params.append("client_id","gateway-client");
       params.append("client_secret","123456");
       params.append("grant_type","password");
      //3.发送异步请求
       axios.post(url, params).then((response) => {
          alert("login ok");
           let result=response.data;
           localStorage.setItem("accessToken",result.access_token);
            location.href="/fileupload.html";
          }).catch((error)=>{
                    console.log(error);
         })
       }

页面写好以后,启动服务进行登录测试即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值