美文网首页
Security 、 shiro 和oauth2三方认证登录de

Security 、 shiro 和oauth2三方认证登录de

作者: Snail127 | 来源:发表于2019-01-08 10:27 被阅读0次

    security 入门教程推荐(此教程写的很基础,解释也比较详细,security入门优质教程)
    社区 Spring Security 从入门到进阶系列教程

    项目地址:https://github.com/athc/hippo

    spring security

    spring boot 整合 security

    org.springframework.security.core.userdetails.User
    org.springframework.security.core.userdetails.UserDetails   
    

    1 . 实现UserDetailsService的loadUserByUsername方法,作用是从数据库获取用户信息

    //给自定义认证方式添加加密方式,在userDetailsService将密码交给security去验证,在认证管理中配置密码验证方式
    @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
      return new User(userInfo.getAccount(), userInfo.getPassword(), roles);
    }
    

    2 . 实现AuthenticationProvider的authenticate方法根据UserDetails实现类获取用户信息进行用户密码,状态等相关验证

    3 . 告诉security认证方式

      /**
     * 添加自定义登录到认证security管理
     * 
     */
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
      //用户认证逻辑,这里可以只配置userAuthenticationProvider 剩下的逻辑判断在provider中完成,如果配置了userDetailsService会去验证密码
      auth.authenticationProvider(userAuthenticationProvider)
              //获取用户信息
         // .userDetailsService(userDetailsService) 
          //密码加密方式
          //.passwordEncoder(passwordEncoder());
    }
    

    4 . 访问资源控制,http.authorizeRequests()方法有多个子节点,每个macher按照他们的声明顺序执行,路径配置顺序有要求 ,匹配就返回.
    hasAnyAuthority("USER")需要有USER权限才能访问;
    hasAnyRole("ADMIN")会自动给ADMIN加上ROLE_前缀,需要有ROLE_ADMIN角色才能访问。

    /**
         * security 拦截路径
         * http.authorizeRequests()方法有多个子节点,每个macher按照他们的声明顺序执行
         * 路径配置顺序有要求 ,匹配就返回
         *
         * @param http
         * @throws Exception
         */
        @Override protected void configure(HttpSecurity http) throws Exception {
          http.csrf().disable()
              .authorizeRequests()
              .antMatchers("/security/login/**").permitAll()
              .antMatchers("/security/user/**").hasAnyAuthority("USER")
              .antMatchers("/security/role/**").hasAnyRole("ADMIN")
              .anyRequest().authenticated()
              .and()
              .rememberMe()
              .key("my-secret")
              .rememberMeCookieName("my-cookie-name")
              .tokenValiditySeconds(24 * 60 * 60)
              .and()
              .formLogin()
              .and()
              .logout()
              .and()
              .httpBasic()
          ;
          // 在 UsernamePasswordAuthenticationFilter 前添加自定义过滤器 BeforeLoginFilter 
          http.addFilterBefore(new BeforeLoginFilter(), UsernamePasswordAuthenticationFilter.class);
        }
    

    整合oauth2

    项目地址:https://github.com/athc/hippo/tree/master/oauth2-security

    security-oauth2区分了客户端和用户。

    5 . 实现ClientDetailsService的loadClientByClientId方法,实现客户端认证

    6 . 配置认证server(@EnableAuthorizationServer)通过继承AuthorizationServerConfigurerAdapter配置认证oauth2自定义客户端和用户认证

    //client认证
    @Override
      public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetailsService);
      }
    
      @Override
      public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints
                //token存储位置
            .tokenStore(new InMemoryTokenStore())
            //将web security配置的authenticationManager
            .authenticationManager(authenticationManager)
            //刷新token会用到userDetailsService
            .userDetailsService(userDetailsService)
            .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
      }
    
      @Override
      public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
        //允许验证token 接口访问,单点登录会访问这个接口验证token是否有效
        oauthServer.checkTokenAccess("permitAll()");
        //加密方式
        oauthServer.passwordEncoder(passwordEncoder());
        //允许表单认证
        oauthServer.allowFormAuthenticationForClients();
      }
    

    7 . 修改security的资源控制,不拦截oauth2资源

    @Override protected void configure(HttpSecurity http) throws Exception {
          http
              .authorizeRequests()
              .antMatchers("/oauth/*").permitAll()
              .and().httpBasic()
          ;
        }
        
       /**
          * 在这security中,把AuthenticationManager交给Spring,
          * 这一步的配置是必不可少的,否则SpringBoot会自动配置一个AuthenticationManager,覆盖掉内存中的用户
          */
         @Bean
         @Override
         public AuthenticationManager authenticationManagerBean() throws Exception {
           AuthenticationManager manager = super.authenticationManagerBean();
           return manager;
         }
    

    8 . 配置资源server(@EnableResourceServer) 继承ResourceServerConfigurerAdapter配置oauth2资源控制

    @Configuration
    @EnableResourceServer
    class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
    
      @Override
      public void configure(ResourceServerSecurityConfigurer resources) {
        //资源id和loadClientByClientId查询到的相匹配
        resources.resourceId("API");
      }
    
      @Override
      public void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            //必须认证过后才可以访问
            .antMatchers("/security/user/**").hasAnyAuthority("USER")
            .antMatchers("/security/role/**").hasAnyRole("ADMIN")
            .anyRequest().permitAll()
        ;
      }
    }
    
    /**
     * oauth2 几种获取token方式 client 可用basic 方式传递
     * refresh token: http://localhost:8013/oauth/token?grant_type=refresh_token&refresh_token=3680e51e-fbf4-417a-85d9-6a8205c14c0a&client_id=user&client_secret=123456
     * client: http://localhost:8013/oauth/token?client_id=user&client_secret=123456&scope=read&grant_type=client_credentials
     * password: http://localhost:8013/oauth/token?username=zhangsan&password=123456&grant_type=password&scope=read&client_id=user&client_secret=1234567
     * authorization code: http://localhost:8013/oauth/authorize?response_type=code&client_id=code&redirect_uri=http://localhost:8013/security/login&scope=all
     */
    

    整合oauth2 短信认证登录

    项目地址:https://github.com/athc/hippo/tree/master/oauth-third

    1 拦截器拦截短信验证登录

    继承认证拦截器AbstractAuthenticationProcessingFilter,重写认证方法
    获取到手机号验证码,组装认证认证的Token类,提交认证
    流程大致为:

    1 拦截短信认证登录,提交短信认证

    2 短信认证逻辑处理,认证成功,提交认证信息

    3 生成 token

    @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
     //短信验证预处理  
     if (!RequestMethod.POST.name().equals(request.getMethod())) {
         throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
       }
       String mobile = request.getParameter("mobile").trim();
       String code = request.getParameter("code").trim();
       if (mobile.isEmpty() || code.isEmpty()) {
         throw new VerifyException("mobile or code cant be null");
       }
       
       //组装认证参数
       SmsToken authRequest = new SmsToken(mobile, code, new ArrayList<SimpleGrantedAuthority>());
       setDetails(request, authRequest);
       //提交authenticationManager 认证
      
       return this.getAuthenticationManager().authenticate(authRequest);
     }
    

    security 配置短信认证 逻辑处理provider

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
      //密码认证
      auth
          .authenticationProvider(userAuthenticationProvider)
          .userDetailsService(userDetailsService)
          //密码验证方式
          .passwordEncoder(new BCryptPasswordEncoder())
      ;
      //sms认证
      auth
          .authenticationProvider(smsProvider)
          .userDetailsService(userDetailsService)
      ;
    }
    

    类似 用户名密码认证的短信认证 provider

    @Override public Authentication authenticate(Authentication authentication) {
     //短信验证码逻辑处理
       SmsToken token = (SmsToken) authentication;
       String mobile = (String) token.getPrincipal();
       String code = (String) token.getCredentials();
       UserDetails user = userDetailsService.loadUserByUsername(mobile);
       logger.info(code);
       //fixme: 验证code
       if (code != code) {
         throw new CredentialsExpiredException("$code expired.");
       }
       //返回认证完成Token
       return new SmsToken(user, null, user.getAuthorities());
     }
    
    //支持自定义Token
     @Override public boolean supports(Class<?> authentication) {
       return SmsToken.class.isAssignableFrom(authentication);
     }
    

    整合oauth2 三方认证登录

    项目地址:https://github.com/athc/hippo/tree/master/oauth-third

    参数注入到类

    @Bean
      @ConfigurationProperties("sina.client")
      public AuthorizationCodeResourceDetails sina() {
        return new AuthorizationCodeResourceDetails();
      }
    
      @Bean
      @Qualifier("sinaResource")
      @Primary
      @ConfigurationProperties("sina.resource")
      public ResourceServerProperties sinaResource() {
        return new ResourceServerProperties();
      }
    

    三方登录请求拦截

     private Filter ssoFilter() {
        CompositeFilter filter = new CompositeFilter();
        List<Filter> filters = new ArrayList<>();
        OAuth2ClientAuthenticationProcessingFilter sinaFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/sina");
        OAuth2RestTemplate sinaTemplate = new OAuth2RestTemplate(sina(), oauth2ClientContext);
        sinaFilter.setRestTemplate(sinaTemplate);
        //自定义userInfo 获取
        SinaUserInfoTokenServices sinaTokenServices = new SinaUserInfoTokenServices(sinaResource().getUserInfoUri(), sina().getClientId());
        sinaTokenServices.setRestTemplate(sinaTemplate);
        sinaFilter.setTokenServices(sinaTokenServices);
        //认证成功处理
        sinaFilter.setAuthenticationSuccessHandler(authSuccessHandler);
        //获取到三方信息 自定义处理 存库等
        sinaTokenServices.setAuthoritiesExtractor(new MyAuthoritiesExtractor());
        //三方登录权限处理
        sinaTokenServices.setPrincipalExtractor(new MyPrincipalExtractor());
        filters.add(sinaFilter);
        filter.setFilters(filters);
        return filter;
      }
    

    将拦截器放到拦截链中

    自定义token:

    实现自定义token产生
    public class UserTokenEnhancer implements TokenEnhancer {
      @Override public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        DefaultOAuth2AccessToken result = (DefaultOAuth2AccessToken) accessToken;
        //uuid 去掉   `-`
        result.setValue(result.getValue().replace("-", ""));
        result.setRefreshToken(new DefaultOAuth2RefreshToken(UUID.randomUUID().toString().replace("-", "")));
        //todo: 这里可以自定义token数据结构
        return result;
      }
    }
    

    从获取的三方信息中 获取有用的信息

    MyPrincipalExtractor implements PrincipalExtractor

    三方认证登录获取的权限

    MyAuthoritiesExtractor implements AuthoritiesExtractor

    security+oauth2+sso demo地址:https://github.com/athc/ath-cloud -----用的kotlin写的单点登录demo

    参考链接:
    https://spring.io/guides/tutorials/spring-boot-oauth2/

    相关文章

      网友评论

          本文标题:Security 、 shiro 和oauth2三方认证登录de

          本文链接:https://www.haomeiwen.com/subject/bgcvrqtx.html