我们知道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 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 granters = new ArrayList<>(Collections.singletonList(endpoints.getTokenGranter()));
granters.add(new AccountRoleTokenGranter(
endpoints.getTokenServices(),
endpoints.getClientDetailsService(),
endpoints.getOAuth2RequestFactory(),
userRoleDetailService));
return new CompositeTokenGranter(granters);
}
参考资料:
https://github.com/spring-projects/spring-security-oauth/blob/master/tests/annotation/custom-grant/src/main/java/demo/Application.java