当前位置: 首页 > 知识库问答 >
问题:

Spring Security OAuth2的Web和移动客户端

咸琪
2023-03-14

我正试图了解OAuth2和SpringSecurityOAuth,尤其是OAuth提供者服务。我正在尝试实现以下内容:

  1. OAuth提供商
  2. 资源服务器(应使用OAuth提供程序(1)保护的RESTful Web服务)
  3. Web客户端(使用Spring Security性保护的Web客户端应用程序,但应使用OAuth提供程序(1)对用户进行身份验证
  4. 本机移动客户端(Android和iOS)也应该使用OAuth提供程序(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)的实现:

OAuth2服务器配置(大部分代码取自此处)

@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()");
    }
}

Web安全配置

@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(定制UserDetailsService)

@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);
    }
}

配置(大多数框架代码取自此示例)

@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个答案

端木桐
2023-03-14

如何实现Web客户机项目,以便当用户登录到受保护的页面或单击登录按钮时,可以重定向到OAuth提供程序url、登录,并在Web客户机上使用所有用户角色进行身份验证,还需要知道使用了哪个客户机

您希望将OAuth用作SSO。

方案1、使用Spring云https://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v

选项2,手动处理SSO过程:

在Web客户端中,使用授权授予将登录页面配置到OAuth服务器。

protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable(); // TODO. Enable this!!!
    http.authorizeRequests()
    .and()
    .formLogin()
    .loginPage("http://oauth.web.com/oauth/authorize?response_type=code&client_id=webclient&redirect_uri=http://web.com") // manually defining page to login
    //.failureUrl("/login?error") // manually defining page for login error
    .usernameParameter("email")
    .permitAll()   
    .and()
    .logout()
    //.logoutUrl("/logout")
    .logoutSuccessUrl("/")
    .permitAll();
}

身份验证和授权过程完成后,您将被重定向到具有授权代码http://web.com/?code=jYWioI。您的web客户端应该在oauth服务器上使用令牌访问权交换此代码。在oauth服务器上,创建用于检索用户信息的endpoint

@RestController
public class UserRestService {

  @RequestMapping("/user")
  public Principal user(Principal user) {
    // you can also return User object with it's roles
    // {"details":...,"principal":{"username":"user",...},"name":"user"}
    return user;
  }

}

然后,web客户端可以通过向上述restendpoint发送带有令牌访问权的请求来访问用户详细信息,并根据响应对用户进行身份验证。

我必须管理访问令牌并始终将其包含在对资源服务器的调用中,还是可以自动完成?

每个请求都必须包括令牌访问。如果你想自动完成,Spring提供了Oauth 2客户端http://projects.spring.io/spring-security-oauth/docs/oauth2.html

在我将要开发的移动应用程序上实现安全性的最佳方法是什么。我是否应该使用密码盛大进行此身份验证,因为应用程序将由我构建,我将在本机屏幕中拥有用户名和密码,然后通过SSL发送到服务器作为基本身份验证?

由于您使用的是本机屏幕,密码授权就足够了,但您可以存储刷新令牌,这将使您能够请求令牌访问,而无需重复身份验证过程

是否有任何示例可以让我查看与SpringSecurityOAuth的对话并返回用户详细信息。

请参阅上面的示例代码或查看此https://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v

 类似资料:
  • 我在使用PHP 5.3和php 5.5的Guzzev3.9.2。 我有以下使用ssl客户端证书的工作curl代码: 我试图把它移到古兹尔: 当我使用curl运行它时,得到了200个响应。当我用口香糖的时候,我得到了403分。

  • 问的很多很杂,完全无八股文,所以记得也不是很清楚了~ 1 自我介绍 2 提到了在快手实习,请问实习期间你觉得印象比较深刻的事情是什么 3 客户端开发与你参加实习之前的看法有什么不同 4 工程开发与自己的项目开发有什么区别 5 我简历上有一个和cpu有关的实验课,深挖和扩展了cpu和内存方面的问题 6 还有一些记不清了,大概都是结合项目问一下开放性的问题 7 手撕 string 转int 力扣原题

  • 面了几家就米哈油的最特别,感觉全程在动脑子😆 先是项目 然后八股问了ipc虚拟内存和智能指针 然后就是几个实际问题 第一个是对比如lru算法的情景,用什么数据结构去存储 第二个是对于一个数组,大部分元素出现两次,一个元素出现一次,怎么找到 然后进阶成大部分三次 第三个问题是最短路径的问题,给一个求最短路径的黑盒算法,可以任意把一条边的长度改为原来的一半,求最短路径。 然后进阶成改两条边。 这些面

  • 关于SAML及其通过Shibboleth的实现,我有很多问题。我已经做了大量的研究,我想澄清一些事情。我有一个与服务器通信的移动应用程序。我们的一个企业客户,我们称之为StackOverflow大学,希望使用Shibboleth(或者我应该说SAML?)为我们的系统提供SSO。他们已经给我们发送了所有学生的电子邮件地址和基本资料。使用OAuth2,我们确切地知道如何提供SSO,但是,使用SAML,

  • 二面结束秒挂,鉴定为KPI 秋招最无语的面试,语气让人极其不舒服,全程冷场好几次😅跟一面面试官没法比 ———————————————————————————————————————— 一面面试官人很好,体验很不错 先问实习经历,看我是iOS实习,问了下做的工作,然后问了很多iOS的知识(不具有普遍性就不写了),一开始还能勉强答,越问越深,被问懵了(吐槽一下,这哪里是校招,问的感觉跟社招一样了)

  • pcg移动客户端实习 一面(3.12,接近2h) 忘记录音了,有点不记得了 https是怎么加密的 拷打项目 手搓高精度加法,带小数 设计模式了解吗,你知道哪些设计模式(观察者模式,单例模式) 用你熟悉的语言实现单例模式(只是听过,不会写) 手搓生产者消费者模式 二面(3.14) HR面(3.18) offer(3.20) 占坑慢慢补