OAuth + Security - 6 - 自定义授权模式

我们知道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 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 grantedAuthorities = Sets.newHashSet();
        List 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 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 <[email protected]>
* @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 authorities) { super(username, password, authorities); this.account = username; } public UserCredential(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection 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 granters = new ArrayList<>(Collections.singletonList(endpoints.getTokenGranter()));
    granters.add(new AccountRoleTokenGranter(
            endpoints.getTokenServices(),
            endpoints.getClientDetailsService(),
            endpoints.getOAuth2RequestFactory(),
            userRoleDetailService));
    return new CompositeTokenGranter(granters);
}

OAuth + Security - 6 - 自定义授权模式_第1张图片

参考资料:

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

你可能感兴趣的:(OAuth + Security - 6 - 自定义授权模式)