zoukankan      html  css  js  c++  java
  • spring cloud oauth2(二) 自定义授权类型 图片验证码

    第一部分:关于授权类型 grant_type 的解析

    1. 每种 grant_type 都会有一个对应的 TokenGranter 实现类。
    2. 所有 TokenGranter 实现类都通过 CompositeTokenGranter 中的 tokenGranters 集合存起来。
    3. 然后通过判断 grantType 参数来定位具体使用那个 TokenGranter 实现类来处理授权。

    第二部分:关于授权登录逻辑

    1. 每种 授权方式 都会有一个对应的 AuthenticationProvider 实现类来实现。
    2. 所有 AuthenticationProvider 实现类都通过 ProviderManager 中的 providers 集合存起来。
    3. TokenGranter 类会 new 一个 AuthenticationToken 实现类,如 UsernamePasswordAuthenticationToken 传给 ProviderManager 类。
    4. ProviderManager 则通过 AuthenticationToken 来判断具体使用那个 AuthenticationProvider 实现类来处理授权。
    5. 具体的登录逻辑由 AuthenticationProvider 实现类来实现,如 DaoAuthenticationProvider

    所有的授权类型都会继承 AbstractTokenGranter

    验证码模式其实就是用户名密码模式,无非在校验验证码的时候先检查验证码是否正确

    所有我们直接复制 ResourceOwnerPasswordTokenGranter ,在 getOAuth2Authentication 中增加验证码相关逻辑

    实现图片验证码模式

    • 新建一个 CaptchaTokenGranter 继承 AbstractTokenGranter 申明GRANT_TYPE为验证码类型*captcha* ,复制上诉密码模式的TokenGranter
    • 其中有两个构造函数,第一个是在配置CaptchaTokenGranter时调用,宁外一个是自己内部调用
    package com.Lonni.oauth.granter;
    
    import com.Lonni.common.constant.AuthConstant;
    import com.Lonni.common.utils.StringUtils;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.security.authentication.*;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
    import org.springframework.security.oauth2.provider.*;
    import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
    import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
    
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    /**
     * 图片验证码类型 tokenGranter
     */
    public class CaptchaTokenGranter extends AbstractTokenGranter {
    
    
        private static   final String  GRANT_TYPE="captcha";
        private final  AuthenticationManager authenticationManager;
        private RedisTemplate redisTemplate;
        public CaptchaTokenGranter(AuthenticationManager authenticationManager,
                                   RedisTemplate redisTemplate,
                                   AuthorizationServerTokenServices tokenServices,
                                   ClientDetailsService clientDetailsService,
                                   OAuth2RequestFactory requestFactory) {
            this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
            this.redisTemplate=redisTemplate;
        }
        protected CaptchaTokenGranter(AuthenticationManager authenticationManager,
                                      AuthorizationServerTokenServices tokenServices,
                                      ClientDetailsService clientDetailsService,
                                      OAuth2RequestFactory requestFactory,
                                      String grantType) {
            //调用父类 接管GRANT_TYPE类型
            super(tokenServices, clientDetailsService, requestFactory, grantType);
            this.authenticationManager=authenticationManager;
    
        }
    
        @Override
        protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
            Map<String, String> parameters = new LinkedHashMap<String, String>(tokenRequest.getRequestParameters());
            String username = parameters.get("username");
            String password = parameters.get("password");
            String captcha=parameters.get("captcha");
            if (StringUtils.isEmpty(captcha)){
                throw  new  InvalidGrantException("验证码不能为空!");
            }
            //正式环境放行
    
    //        String key= AuthConstant.AUTH_CATCHA_CACHE_KEY+captcha;
    //        Object o = redisTemplate.opsForValue().get(key);
    //        if (o==null){
    //            throw  new  InvalidGrantException("验证码不存在!");
    //        }
    //        if (!o.toString().equals(captcha)){
    //            throw  new  InvalidGrantException("验证码错误!");
    //        }
            // Protect from downstream leaks of password
            parameters.remove("password");
    
            Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password);
            ((AbstractAuthenticationToken) userAuth).setDetails(parameters);
            try {
                userAuth = authenticationManager.authenticate(userAuth);
            }
            catch (AccountStatusException ase) {
                //covers expired, locked, disabled cases (mentioned in section 5.2, draft 31)
                throw new InvalidGrantException(ase.getMessage());
            }
            catch (BadCredentialsException e) {
                // If the username/password are wrong the spec says we should send 400/invalid grant
                throw new InvalidGrantException(e.getMessage());
            }
            if (userAuth == null || !userAuth.isAuthenticated()) {
                throw new InvalidGrantException("Could not authenticate user: " + username);
            }
    
            OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
            return new OAuth2Authentication(storedOAuth2Request, userAuth);
    
    
        }
    }
    

    建立TokenGranter扩展类,将自定义的TokenGranter加入到系统默认的列表中

    package com.Lonni.oauth.granter;
    
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
    import org.springframework.security.oauth2.provider.CompositeTokenGranter;
    import org.springframework.security.oauth2.provider.TokenGranter;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    /**
     * TokenGranter 扩展 将自定义的grant_type类型添加到oauth2中
     * 使用方法:
     * 在configure(AuthorizationServerEndpointsConfigurer endpoints)中:
     * //获取自定义tokenGranter
     *      TokenGranter tokenGranter = TokenGranterExt.getTokenGranter(authenticationManager, endpoints, baseRedis, userClient, socialProperties);
     *      endpoints.tokenGranter(tokenGranter);
     *
     */
    public class TokenGranterExt {
    
        public static TokenGranter getTokenGranter(final AuthenticationManager authenticationManager,
                                                   final AuthorizationServerEndpointsConfigurer endpointsConfigurer,
                                                   RedisTemplate redisTemplate
        ) {
    
            //  默认tokenGranter集合 security 自带的
            List<TokenGranter> granters = new ArrayList<>(Collections.singletonList(endpointsConfigurer.getTokenGranter()));
            //添加验证码
            granters.add(new CaptchaTokenGranter(authenticationManager,  redisTemplate, endpointsConfigurer.getTokenServices(), endpointsConfigurer.getClientDetailsService(), endpointsConfigurer.getOAuth2RequestFactory()));
            return new CompositeTokenGranter(granters);
        }
    
    }
    

    在授权服务配置中加入所有的TokenGranter

    在 AuthorizationServerConfigurerAdapter 实现类的 configure*(*AuthorizationServerEndpointsConfigurer endpoints*)*方法增加

    //获取grant_type类型组合
            TokenGranter tokenGranter = TokenGranterExt.getTokenGranter(authenticationManager, endpoints,  redisTemplate);
    
    
            endpoints
                    //设置密码模式认证器
                    .authenticationManager(authenticationManager)
                    //设置授权码模式认证器
                    .authorizationCodeServices(this.authorizationCodeServices())
                    //.authorizationCodeServices(new JdbcAuthorizationCodeServices(dataSource))
    
                    //设置令牌策略
                    .tokenServices(tokenServices())
                    //设置查询用户的userDetilService
                    .userDetailsService(userDetailsService)
                    //设置grant_type类型集合
                    .tokenGranter(tokenGranter)
    
                    //允许post get提交认证
                    .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
    
  • 相关阅读:
    根据自己的博客数据统计国内IT人群
    使用dropwizard(5)--加入swagger
    使用dropwizard(4)-加入测试-jacoco代码覆盖率
    使用dropwizard(3)-加入DI-dagger2
    收藏博客
    IntelliJ IDEA 下载安装(含注册码)
    fontawesome图标字体库组件在服务器上显示不出来图标的解决
    MySQL DBA工作角色和职责介绍
    MySQL主主复制(双主复制)配置过程介绍
    MySQL表与表之间的SQL Joins图介绍
  • 原文地址:https://www.cnblogs.com/HiLzd/p/14367839.html
Copyright © 2011-2022 走看看