Spring 启动 Azure AD 自定义角色
Spring Boot Azure AD custom roles
我有这个香草 spring boot/azure/starter 应用程序,连接到我们的内部 azure 服务。
https://docs.microsoft.com/de-de/azure/developer/java/spring-framework/configure-spring-boot-starter-java-app-with-azure-active-directory
通常它按设计工作。
如果我想为授权添加自定义角色,我有哪些选择?
我想要那个流程:
- 使用 user/pw 登录到 azure(按预期工作)
- 从本地数据库 (postgres) 加载用户角色
- Inject/Add 这个角色进入 spring 的
GrantedAuthority
列表
对于 spring 安全性,我们通常使用自定义 AuthenticationProvider
目前我有这个工作代码:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends AadWebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.authorizeHttpRequests()
.anyRequest()
.authenticated()
.and()
.oauth2Login();
}
}
我想要这样的东西:
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Slf4j
public class ThdAuthenticationProvider implements AuthenticationProvider {
private final
@NonNull
IApplicationUserService userService;
/**
* Performs authentication with the same contract as .
*
* @param authentication the authentication request object.
* @return a fully authenticated object including credentials. May return <code>null</code> if the
* <code>AuthenticationProvider</code> is unable to support authentication of the passed
* <code>Authentication</code> object. In such a case, the next <code>AuthenticationProvider</code> that
* supports the presented <code>Authentication</code> class will be tried.
* @throws AuthenticationException if authentication fails.
*/
@Override
public org.springframework.security.core.Authentication authenticate(org.springframework.security.core.Authentication
authentication)
throws AuthenticationException {
final String name = authentication.getName().toLowerCase();
final String password = authentication.getCredentials().toString();
// go to azure, login with name/password
// come back if sucessfull
List<String> roles = userService.fetchRoles(name);
List<GrantedAuthority> grantedAuth = new ArrayList<>();
grantedAuth.addAll(roles);
return new UsernamePasswordAuthenticationToken(name, password, grantedAuth);
}
编辑
我的自定义用户服务 - 从数据库或其他地方获取角色的位置:
@Service
public class UserService {
List<String> fetchUserRoles(String user){
return List.of("Administrator", "Product Owner", "Developer");
}
}
我的自定义安全链应用了这些角色:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends AadWebSecurityConfigurerAdapter {
private final UserService userService;
@Autowired
public SecurityConfiguration(UserService userService) {
this.userService = userService;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.authorizeHttpRequests()
.anyRequest()
.authenticated()
.and()
.oauth2Login()
.userInfoEndpoint(userInfoEndpointConfig -> {
userInfoEndpointConfig.oidcUserService(this.oidcUserService());
});
}
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
final OidcUserService delegate = new OidcUserService();
return (userRequest) -> {
// Delegate to the default implementation for loading a user
OidcUser oidcUser = delegate.loadUser(userRequest);
OAuth2AccessToken accessToken = userRequest.getAccessToken();
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
// TODO
// 1) Fetch the authority information from the protected resource using accessToken
// 2) Map the authority information to one or more GrantedAuthority's and add it to mappedAuthorities
// 3) Create a copy of oidcUser but use the mappedAuthorities instead
List<String> dummy = userService.fetchUserRoles("dummy");
dummy.forEach(user -> mappedAuthorities.add((GrantedAuthority) () -> user));
oidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
return oidcUser;
};
}
}
Spring Boot Azure AD custom roles
请看下面link里面有详细的解释:
注册网络API应用程序并配置API范围
为用户分配这些角色
在 Azure AD 中注册客户端应用程序并配置 API 权限
参考:
@thomas-lang 非常感谢托马斯!!!你的post帮了我大忙!
附上我的代码变体
用户服务
@Service
public class UserService {
private final PeopleService peopleService;
public UserService(PeopleService peopleService) {
this.peopleService = peopleService;
}
public Set<Role> fetchUserRoles(String user, String email){
Person loggedPerson = peopleService.findPersonByEmail(email);
return loggedPerson.getRoles();
}
}
安全配置
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfigurationAad extends AadWebSecurityConfigurerAdapter {
private final UserService userService;
@Autowired
public SecurityConfigurationAad(UserService userService) {
this.userService = userService;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.authorizeHttpRequests()
.anyRequest()
.authenticated()
.and()
.oauth2Login()
.userInfoEndpoint(userInfoEndpointConfig -> {
userInfoEndpointConfig.oidcUserService(this.oidcUserService());
});
}
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
final OidcUserService delegate = new OidcUserService();
return (userRequest) -> {
// Delegate to the default implementation for loading a user
OidcUser oidcUser = delegate.loadUser(userRequest);
DecodedToken token = DecodedToken.getDecoded(userRequest.getAccessToken().getTokenValue());
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
// TODO
// 1) Fetch the authority information from the protected resource using accessToken
// 2) Map the authority information to one or more GrantedAuthority's and add it to mappedAuthorities
// 3) Create a copy of oidcUser but use the mappedAuthorities instead
Set<Role> dummy = userService.fetchUserRoles("dummy", token.unique_name);
dummy.forEach(user -> mappedAuthorities.add((GrantedAuthority) () -> String.valueOf(user)));
oidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
return oidcUser;
};
}
}
我从这里得到的 DecodedToken 实现
https://www.lenar.io/how-to-decode-jwt-authentication-token/
我有这个香草 spring boot/azure/starter 应用程序,连接到我们的内部 azure 服务。 https://docs.microsoft.com/de-de/azure/developer/java/spring-framework/configure-spring-boot-starter-java-app-with-azure-active-directory
通常它按设计工作。
如果我想为授权添加自定义角色,我有哪些选择?
我想要那个流程:
- 使用 user/pw 登录到 azure(按预期工作)
- 从本地数据库 (postgres) 加载用户角色
- Inject/Add 这个角色进入 spring 的
GrantedAuthority
列表
对于 spring 安全性,我们通常使用自定义 AuthenticationProvider
目前我有这个工作代码:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends AadWebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.authorizeHttpRequests()
.anyRequest()
.authenticated()
.and()
.oauth2Login();
}
}
我想要这样的东西:
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Slf4j
public class ThdAuthenticationProvider implements AuthenticationProvider {
private final
@NonNull
IApplicationUserService userService;
/**
* Performs authentication with the same contract as .
*
* @param authentication the authentication request object.
* @return a fully authenticated object including credentials. May return <code>null</code> if the
* <code>AuthenticationProvider</code> is unable to support authentication of the passed
* <code>Authentication</code> object. In such a case, the next <code>AuthenticationProvider</code> that
* supports the presented <code>Authentication</code> class will be tried.
* @throws AuthenticationException if authentication fails.
*/
@Override
public org.springframework.security.core.Authentication authenticate(org.springframework.security.core.Authentication
authentication)
throws AuthenticationException {
final String name = authentication.getName().toLowerCase();
final String password = authentication.getCredentials().toString();
// go to azure, login with name/password
// come back if sucessfull
List<String> roles = userService.fetchRoles(name);
List<GrantedAuthority> grantedAuth = new ArrayList<>();
grantedAuth.addAll(roles);
return new UsernamePasswordAuthenticationToken(name, password, grantedAuth);
}
编辑
我的自定义用户服务 - 从数据库或其他地方获取角色的位置:
@Service
public class UserService {
List<String> fetchUserRoles(String user){
return List.of("Administrator", "Product Owner", "Developer");
}
}
我的自定义安全链应用了这些角色:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends AadWebSecurityConfigurerAdapter {
private final UserService userService;
@Autowired
public SecurityConfiguration(UserService userService) {
this.userService = userService;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.authorizeHttpRequests()
.anyRequest()
.authenticated()
.and()
.oauth2Login()
.userInfoEndpoint(userInfoEndpointConfig -> {
userInfoEndpointConfig.oidcUserService(this.oidcUserService());
});
}
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
final OidcUserService delegate = new OidcUserService();
return (userRequest) -> {
// Delegate to the default implementation for loading a user
OidcUser oidcUser = delegate.loadUser(userRequest);
OAuth2AccessToken accessToken = userRequest.getAccessToken();
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
// TODO
// 1) Fetch the authority information from the protected resource using accessToken
// 2) Map the authority information to one or more GrantedAuthority's and add it to mappedAuthorities
// 3) Create a copy of oidcUser but use the mappedAuthorities instead
List<String> dummy = userService.fetchUserRoles("dummy");
dummy.forEach(user -> mappedAuthorities.add((GrantedAuthority) () -> user));
oidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
return oidcUser;
};
}
}
Spring Boot Azure AD custom roles
请看下面link里面有详细的解释:
注册网络API应用程序并配置API范围
为用户分配这些角色
在 Azure AD 中注册客户端应用程序并配置 API 权限
参考:
@thomas-lang 非常感谢托马斯!!!你的post帮了我大忙!
附上我的代码变体
用户服务
@Service
public class UserService {
private final PeopleService peopleService;
public UserService(PeopleService peopleService) {
this.peopleService = peopleService;
}
public Set<Role> fetchUserRoles(String user, String email){
Person loggedPerson = peopleService.findPersonByEmail(email);
return loggedPerson.getRoles();
}
}
安全配置
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfigurationAad extends AadWebSecurityConfigurerAdapter {
private final UserService userService;
@Autowired
public SecurityConfigurationAad(UserService userService) {
this.userService = userService;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.authorizeHttpRequests()
.anyRequest()
.authenticated()
.and()
.oauth2Login()
.userInfoEndpoint(userInfoEndpointConfig -> {
userInfoEndpointConfig.oidcUserService(this.oidcUserService());
});
}
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
final OidcUserService delegate = new OidcUserService();
return (userRequest) -> {
// Delegate to the default implementation for loading a user
OidcUser oidcUser = delegate.loadUser(userRequest);
DecodedToken token = DecodedToken.getDecoded(userRequest.getAccessToken().getTokenValue());
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
// TODO
// 1) Fetch the authority information from the protected resource using accessToken
// 2) Map the authority information to one or more GrantedAuthority's and add it to mappedAuthorities
// 3) Create a copy of oidcUser but use the mappedAuthorities instead
Set<Role> dummy = userService.fetchUserRoles("dummy", token.unique_name);
dummy.forEach(user -> mappedAuthorities.add((GrantedAuthority) () -> String.valueOf(user)));
oidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
return oidcUser;
};
}
}
我从这里得到的 DecodedToken 实现
https://www.lenar.io/how-to-decode-jwt-authentication-token/