OAuth + Security - 6 - 自定義授權(quán)模式

我們知道OAuth2的官方提供了四種令牌的獲取,簡(jiǎn)化模式,授權(quán)碼模式,密碼模式,客戶端模式。其中密碼模式中僅僅支持我們通過用戶名和密碼的方式獲取令牌,那么我們?nèi)绾稳?shí)現(xiàn)一個(gè)我們自己的令牌獲取的模式呢?下面我們將以用戶名,密碼,角色三個(gè)信息的方式來獲取令牌。

在授權(quán)模式中,授權(quán)模式的核心接口是 TokenGranter ,他擁有一個(gè)抽象實(shí)現(xiàn)類 AbstractTokenGranter ,我們需要自定義新的 grant type ,就再寫一個(gè)他的子類即可,如下:

public class AccountRoleTokenGranter extends AbstractTokenGranter {

    private static final String GRANT_TYPE = "password_role";
    
    // 獲取用戶信息的實(shí)現(xiàn)
    private UserRoleDetailServiceImpl userRoleDetailService;

    /**
     * 構(gòu)造方法提供一些必要的注入的參數(shù)
     * 通過這些參數(shù)來完成我們父類的構(gòu)建
     *
     * @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;
    }

    /**
     * 在這里查詢我們用戶,構(gòu)建用戶的授權(quán)信息
     *
     * @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("用戶角色不存在");
        }
        // 構(gòu)建用戶授權(quán)信息
        Authentication user = new AccountRoleAuthenticationToken(userDetails.getUsername(),
                userDetails.getPassword(), userDetails.getAuthorities());
        return new OAuth2Authentication(tokenRequest.createOAuth2Request(client), user);
    }

}

配置用戶信息獲取實(shí)現(xiàn)類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 {
        // 查詢相應(yīng)用戶
        UserDetailDTO userCredential = userService.findByAccountAndRole(account, roles);

        if (ObjectUtils.isEmpty(userCredential)) {
            throw new UsernameNotFoundException("該賬號(hào)角色不存在!");
        }

        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_開頭,可以在數(shù)據(jù)庫中設(shè)置
                    GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getRoleName());
                    grantedAuthorities.add(grantedAuthority);
                    //獲取權(quán)限
                    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;

    }
}

/**
 * 認(rèn)證用戶信息類
 *
 * @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存儲(chǔ)源
            .tokenStore(tokenStore())
            // 配置權(quán)限管理
            .authenticationManager(authenticationManager);
    endpoints.tokenGranter(tokenGranter(endpoints));
}

/**
 * 重點(diǎn)
 * 先獲取已經(jīng)有的五種授權(quán),然后添加我們自己的進(jìn)去
 *
 * @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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容