• OAuth + Security


    我们知道OAuth2的官方提供了四种令牌的获取,简化模式,授权码模式,密码模式,客户端模式。其中密码模式中仅仅支持我们通过用户名和密码的方式获取令牌,那么我们如何去实现一个我们自己的令牌获取的模式呢?下面我们将以用户名,密码,角色三个信息的方式来获取令牌。

    在授权模式中,授权模式的核心接口是 TokenGranter ,他拥有一个抽象实现类 AbstractTokenGranter ,我们需要自定义新的 grant type ,就再写一个他的子类即可,如下:

    public class AccountRoleTokenGranter extends AbstractTokenGranter {
    
        private static final String GRANT_TYPE = "password_role";
        
        // 获取用户信息的实现
        private UserRoleDetailServiceImpl userRoleDetailService;
    
        /**
         * 构造方法提供一些必要的注入的参数
         * 通过这些参数来完成我们父类的构建
         *
         * @param tokenServices         tokenServices
         * @param clientDetailsService  clientDetailsService
         * @param oAuth2RequestFactory  oAuth2RequestFactory
         * @param userRoleDetailService userDetailsService
         */
        public AccountRoleTokenGranter(AuthorizationServerTokenServices tokenServices,
                                       ClientDetailsService clientDetailsService,
                                       OAuth2RequestFactory oAuth2RequestFactory,
                                       UserRoleDetailServiceImpl userRoleDetailService) {
            super(tokenServices, clientDetailsService, oAuth2RequestFactory, GRANT_TYPE);
            this.userRoleDetailService = userRoleDetailService;
        }
    
        /**
         * 在这里查询我们用户,构建用户的授权信息
         *
         * @param client       客户端
         * @param tokenRequest tokenRequest
         * @return OAuth2Authentication
         */
        @Override
        protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
            Map<String, String> params = tokenRequest.getRequestParameters();
            String account = params.getOrDefault("username", "");
            String role = params.getOrDefault("role", "");
    
            // 获取用户信息
            UserDetails userDetails = userRoleDetailService.loadUserByAccountAndRole(account, role);
            if (ObjectUtil.isNull(userDetails)) {
                throw new UsernameNotFoundException("用户角色不存在");
            }
            // 构建用户授权信息
            Authentication user = new AccountRoleAuthenticationToken(userDetails.getUsername(),
                    userDetails.getPassword(), userDetails.getAuthorities());
            return new OAuth2Authentication(tokenRequest.createOAuth2Request(client), user);
        }
    
    }
    

    配置用户信息获取实现类UserRoleDetailServiceImpl

    @Service
    public class UserRoleDetailServiceImpl {
    
        private UserService userService;
        private RoleService roleService;
    
        @Autowired
        public UserRoleDetailServiceImpl(UserService userService, RoleService roleService) {
            this.userService = userService;
            this.roleService = roleService;
        }
    
        public UserCredential loadUserByAccountAndRole(String account, String roles) throws UsernameNotFoundException {
            // 查询相应用户
            UserDetailDTO userCredential = userService.findByAccountAndRole(account, roles);
    
            if (ObjectUtils.isEmpty(userCredential)) {
                throw new UsernameNotFoundException("该账号角色不存在!");
            }
    
            Set<GrantedAuthority> grantedAuthorities = Sets.newHashSet();
            List<Role> roleResult = userService.findRoleByUserId(Integer.valueOf(userCredential.getUserId()));
            if (!roleResult.isEmpty()) {
                for (Role role : roleResult) {
                    if (StrUtil.equalsIgnoreCase(role.getRoleName(), roles)) {
                        //角色必须是ROLE_开头,可以在数据库中设置
                        GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getRoleName());
                        grantedAuthorities.add(grantedAuthority);
                        //获取权限
                        List<MenuDTO> menuByRoleId = roleService.findMenuByRoleId(role.getRoleId());
                        if (!menuByRoleId.isEmpty()) {
                            for (MenuDTO menu : menuByRoleId) {
                                if (StringUtils.isNotBlank(menu.getPerms())) {
                                    GrantedAuthority authority = new SimpleGrantedAuthority(menu.getPerms());
                                    grantedAuthorities.add(authority);
                                }
                            }
                        }
                    }
    
                }
            }
            UserCredential authUser = new UserCredential(account, userCredential.getPassword(), grantedAuthorities);
            BeanUtils.copyProperties(userCredential, authUser);
            return authUser;
    
        }
    }
    
    /**
     * 认证用户信息类
     *
     * @author zhongyj <1126834403@qq.com><br/>
     * @date 2020/2/25
     */
    @Setter
    @Getter
    public class UserCredential extends User implements Serializable {
    
        private static final long serialVersionUID = 2554837818190360741L;
    
        public static final String DEFAULT_USER = "dimples";
    
        private boolean accountNonExpired = true;
    
        private boolean accountNonLocked = true;
    
        private boolean credentialsNonExpired = true;
    
        private boolean enabled = true;
    
        private Integer userId;
    
        private String userCode;
    
        private String account;
    
        private String username;
    
        private String status;
    
        private Date createDate;
    
        private Date modifyDate;
    
    
        public UserCredential(String username, String password, Collection<? extends GrantedAuthority> authorities) {
            super(username, password, authorities);
            this.account = username;
        }
    
        public UserCredential(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
            super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
        }
    }
    

    接下来就只需将其添加到Oauth2AuthorizationServerConfig 中

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints
                // 配置token存储源
                .tokenStore(tokenStore())
                // 配置权限管理
                .authenticationManager(authenticationManager);
        endpoints.tokenGranter(tokenGranter(endpoints));
    }
    
    /**
     * 重点
     * 先获取已经有的五种授权,然后添加我们自己的进去
     *
     * @param endpoints AuthorizationServerEndpointsConfigurer
     * @return TokenGranter
     */
    private TokenGranter tokenGranter(final AuthorizationServerEndpointsConfigurer endpoints) {
        List<TokenGranter> granters = new ArrayList<>(Collections.singletonList(endpoints.getTokenGranter()));
        granters.add(new AccountRoleTokenGranter(
                endpoints.getTokenServices(),
                endpoints.getClientDetailsService(),
                endpoints.getOAuth2RequestFactory(),
                userRoleDetailService));
        return new CompositeTokenGranter(granters);
    }
    

    image

    参考资料:

    https://github.com/spring-projects/spring-security-oauth/blob/master/tests/annotation/custom-grant/src/main/java/demo/Application.java

  • 相关阅读:
    postgresql 添加触发器
    postgresql 操作
    postgresql 更新自增变量
    java8 stream api 文件流甚是牛逼
    fastjson妙用
    idea中springboot内置tomcat控制台中文乱码解决
    linux中开放某个端口
    idea中application.properties文件防止中文汉字自动转换成unicode编码解决办法
    使用vue开源项目vue-framework-wz遇到的问题以及解决方案
    rsync的使用
  • 原文地址:https://www.cnblogs.com/reroyalup/p/13071157.html
Copyright © 2020-2023  润新知