我试图围绕OAuth2和Spring Security OAuth,特别是OAuth提供商服务 . 我正在尝试实现以下内容:
-
OAuth提供商
-
资源服务器(应使用OAuth Provider(1)保护的RESTful Web服务)
-
Web Client(使用Spring Security保护但应使用OAuth Provider(1)对用户进行身份验证的Web客户端应用程序
-
本机移动客户端(Android和iOS)也应使用OAuth Provider(1)进行身份验证
所有这些模块彼此独立,即在不同的项目中分开,并将托管在不同的域上,例如(1)http://oauth.web.com,(2)http://rest.web.com,(3)http://web.com
我的两个问题是:
A.如何实施Web客户端项目,以便在用户登录受保护页面或单击“登录”按钮时,重定向到OAuth提供者URL,登录,并在具有所有用户角色的Web客户端上进行身份验证,以及同时需要知道使用了哪个客户端 . @EnableResourceServer
(与实现资源服务器的方式相同;请参阅下面的代码)以获取用户的详细信息?我是否必须管理访问令牌并始终将其包含在对资源服务器的调用中,或者它可以以某种方式自动完成?
B.在我将要开发的移动应用程序上实现安全性的最佳方法是什么 . 我是否应该使用密码宏来进行此身份验证,因为应用程序将由我构建,我将在本机屏幕中将用户名和密码作为基本身份验证通过SSL发送到服务器?是否有任何示例我可以查看与Spring Security OAuth的对话并返回用户详细信息 .
这是我对OAuth项目(1)和资源项目(2)的实现:
1. OAuth提供商
OAuth2服务器配置(大部分代码取自HERE)
@Configuration
@EnableAuthorizationServer
public class OAuth2ServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Autowired
DataSource dataSource;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(tokenStore())
.approvalStore(approvalStore())
.authorizationCodeServices(authorizationCodeServices())
;
}
@Bean
public JdbcClientDetailsService clientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Bean
public ApprovalStore approvalStore() {
return new JdbcApprovalStore(dataSource);
}
@Bean
public AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(dataSource);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.checkTokenAccess("permitAll()");
}
}
网络安全配置
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable(); // TODO. Enable this!!!
http.authorizeRequests()
.and()
.formLogin()
// .loginPage("/login") // manually defining page to login
// .failureUrl("/login?error") // manually defining page for login error
.usernameParameter("email")
.permitAll()
.and()
.logout()
// .logoutUrl("/logout")
.logoutSuccessUrl("/")
.permitAll();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(customUserDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
UserDetailsService(customUserDetailsService)
@Service
public class CustomUserDetailsService implements UserDetailsService{
private final UserService userService;
@Autowired
public CustomUserDetailsService(UserService userService) {
this.userService = userService;
}
public Authority loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userService.getByEmail(email)
.orElseThrow(() -> new UsernameNotFoundException(String.format("User with email=%s was not found", email)));
return new Authority(user);
}
}
2.资源服务器(RESTful WS)
配置(大部分框架代码取自THIS示例)
@Configuration
@EnableResourceServer
public class OAuth2ResourceConfig extends ResourceServerConfigurerAdapter{
@Autowired
DataSource dataSource;
String RESOURCE_ID = "data_resource";
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
TokenStore tokenStore = new JdbcTokenStore(dataSource);
resources
.resourceId(RESOURCE_ID)
.tokenStore(tokenStore);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
// For some reason we cant just "permitAll" OPTIONS requests which are needed for CORS support. Spring Security
// will respond with an HTTP 401 nonetheless.
// So we just put all other requests types under OAuth control and exclude OPTIONS.
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/**").access("#oauth2.hasScope('read')")
.antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')")
.antMatchers(HttpMethod.PATCH, "/**").access("#oauth2.hasScope('write')")
.antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')")
.antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('write')")
.and()
// Add headers required for CORS requests.
.headers().addHeaderWriter((request, response) -> {
response.addHeader("Access-Control-Allow-Origin", "*");
if (request.getMethod().equals("OPTIONS")) {
response.setHeader("Access-Control-Allow-Methods", request.getHeader("Access-Control-Request-Method"));
response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"));
}
});
}
}
WS控制器:
@RestController
@RequestMapping(value = "/todos")
public class TodoController {
@Autowired
private TodoRepository todoRepository;
@RequestMapping(method = RequestMethod.GET)
public List<Todo> todos() {
return todoRepository.findAll();
}
// other methods
}
1 回答
您希望将OAuth用作SSO .
选项1,使用spring cloud https://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v
选项2,手动处理SSO过程:
在您的Web客户端中,使用授权授权将登录页面配置为OAuth服务器 .
身份验证和授权过程完成后,您将被重定向到具有授权码
http://web.com/?code=jYWioI
的Web客户端 . 您的Web客户端应该在您的oauth服务器上使用令牌访问权交换此代码 . 在您的oauth服务器上,创建用于检索用户信息的 endpoints然后,您的Web客户端可以通过发送具有对上述休息 endpoints 的令牌访问权限的请求来访问用户详细信息,并根据响应对用户进行身份验证 .
每个请求都必须包含令牌访问 . 如果你想自动完成,spring提供了Oauth 2客户端http://projects.spring.io/spring-security-oauth/docs/oauth2.html
由于您使用的是本机屏幕,因此密码授予就足够了,但您可以存储刷新令牌,这样您就可以请求令牌访问而无需重复身份验证过程 .
看上面的示例代码或看一下https://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v