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

使用空权限成功登录Spring OAuth2

郭意
2023-03-14
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@EnableJpaRepositories(basePackageClasses = UserRepository.class)
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomOAuth2UserService customOAuth2UserService;

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Autowired
    private OAuth2AuthenticationFailureHandler oAuth2AuthenticationFailureHandler;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
        auth
                .userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .formLogin()
                    .loginPage("/login")
                    .failureUrl("/login?error=true")
                    .and()
                .logout()
                    .logoutSuccessUrl("/")
                    .deleteCookies("JSESSIONID")
                    .invalidateHttpSession(true)
                .and()
                .oauth2Login()
                    .loginPage("/login")
                    .failureUrl("/login?error=true")
                .userInfoEndpoint()
                    .userService(customOAuth2UserService)
                .and()
                .failureHandler(oAuth2AuthenticationFailureHandler);
    }


    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

}
@Service
public class CustomOAuth2UserService extends DefaultOAuth2UserService {

    @Autowired
    private UserService userService;

    @Override
    public OAuth2User loadUser(OAuth2UserRequest oAuth2UserRequest) throws OAuth2AuthenticationException {
        OAuth2User oAuth2User = super.loadUser(oAuth2UserRequest);

        try {
            return processOAuth2User(oAuth2UserRequest, oAuth2User);
        }catch (Exception ex) {
            // Throwing an instance of AuthenticationException will trigger the OAuth2AuthenticationFailureHandler
            throw new InternalAuthenticationServiceException(ex.getMessage(), ex.getCause());
        }
    }

    private OAuth2User processOAuth2User(OAuth2UserRequest oAuth2UserRequest, OAuth2User oAuth2User) {
        OAuth2UserInfo oAuth2UserInfo = OAuth2UserInfoFactory.getOAuth2UserInfo(oAuth2UserRequest.getClientRegistration().getRegistrationId(), oAuth2User.getAttributes());
        if(StringUtils.isEmpty(oAuth2UserInfo.getEmail())) {
            throw new RuntimeException("Id not found from OAuth2 provider");
        }

        User user;
        try {
            user = userService.getByEmail(oAuth2UserInfo.getEmail());
            if(!user.getProvider().toString().equalsIgnoreCase(oAuth2UserRequest.getClientRegistration().getRegistrationId())) throw new EmailAlreadyTakenException("email-already-taken");
        } catch (UserNotFoundException e) {
            user = registerNewUser(oAuth2UserRequest, oAuth2UserInfo);
        }

        return new CustomUserDetails(user);
    }

    private User registerNewUser(OAuth2UserRequest oAuth2UserRequest, OAuth2UserInfo oAuth2UserInfo) {
        User user = new User();
        user.setProvider(AuthProvider.valueOf(oAuth2UserRequest.getClientRegistration().getRegistrationId()));
        Identity identity = new Identity(user);
        if(oAuth2UserInfo.getFirstName() != null && !oAuth2UserInfo.getFirstName().equalsIgnoreCase(""))
            identity.setFirstName(oAuth2UserInfo.getFirstName());
        if(oAuth2UserInfo.getLastName() != null && !oAuth2UserInfo.getLastName().equalsIgnoreCase(""))
            identity.setSecondName(oAuth2UserInfo.getLastName());
        user.setIdentity(identity);
        user.setEmail(oAuth2UserInfo.getEmail());
        user.setConfirmedRegistration(true);
        boolean flag = false;
        String username = oAuth2UserInfo.getName().toLowerCase().replaceAll("\\s+", "");
        user.setUsername(username);
        return userService.addFacebookUser(user);

    }

}

这是application.properties文件的一部分:

spring.security.oauth2.client.registration.facebook.client-id=***
spring.security.oauth2.client.registration.facebook.client-secret=***
spring.security.oauth2.client.registration.facebook.scope=email,public_profile

spring.security.oauth2.client.registration.google.client-id=***
spring.security.oauth2.client.registration.google.client-secret=***
spring.security.oauth2.client.registration.google.scope=email,profile


spring.security.oauth2.client.provider.facebook.authorizationUri = https://www.facebook.com/v3.0/dialog/oauth
spring.security.oauth2.client.provider.facebook.tokenUri = https://graph.facebook.com/v3.0/oauth/access_token
spring.security.oauth2.client.provider.facebook.userInfoUri = https://graph.facebook.com/v3.0/me?fields=id,first_name,middle_name,last_name,name,email,verified,is_verified,picture

一旦登录,用户可以调用这个url/users/{username},但是当他通过OAuth2登录facebook或google时,他会被拒绝,因为权威列表是空的。当他用他的webapp凭据登录时,权威列表包含USER_ROLE,他可以继续操作。

@PreAuthorize("hasRole('USER')")
    @GetRequest("users/{username}")
    public String getUser(@PathVariable String username, @PathVariable String subsection, Model model, Principal principal) throws IllegalAccessException, UserNotFoundException {
        User user = userService.getByUsername(principal.getName());
        model.addAttribute("user", user);
        return "user";
    }

主体对象内部有:

    null
    null

共有1个答案

卢志强
2023-03-14

经过一段时间的调试,我找到了解决方案!我没有正确配置用户的角色。在自定义OAuth2UserService的registerNewUser方法中,我没有设置用户的角色。我刚加了一行:

user.setRoles(new HashSet<>(Collections.singletonList(new Role("ROLE_USER"))));

一切都开始奏效了!所以现在,当询问OAuth2User的授权时,它只调用CustomUserDetails(我的OAuth2User的实现)的getAuthorities并调用用户的getRoles方法。

CustomUserDetails类:

public class CustomUserDetails extends User implements UserDetails, OAuth2User {

    public CustomUserDetails() {
    }

    public CustomUserDetails(String username, String email, String password, Set<Role> roles) {
        super(username, email, password, roles);
    }

    public CustomUserDetails(User user) {
        super(user.getUsername(), user.getEmail(), user.getPassword(), user.getRoles());
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return getRoles()
                .stream()
                .map(role -> new SimpleGrantedAuthority(role.getRole()))
                .collect(Collectors.toList());
    }

    @Override
    public Map<String, Object> getAttributes() {
        return null;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    @Override
    public String getName() {
        return null;
    }
}
 类似资料:
  • 问题内容: 我已经看到许多特定的案例,人们在询问,人们在解释两者之间的区别,但我似乎也不能理解一般的区别。这两个是同义词吗?一个暗示另一个吗? 问题答案: 这两个是同义词吗? 号说:“嘿,Android(及相关的发行渠道),请让用户允许我做X”。说:“嘿,Android(及相关的发行渠道),我有兴趣在具有Y功能的硬件上运行”。 如果硬件不符合您的要求,但用户不参与,则可能会将您从Play商店(和其

  • 我已经创建了react应用程序,并使用下面提供的okta示例使用okta登录。 https://developer.okta.com/code/react/okta_react/#add-an-openid-connect-client-in-okta 我可以通过输入凭据并点击登录按钮成功地从我的应用程序登录到应用程序。 但是,如果我登录到okta开发帐户,然后如果我导航到我的应用程序,我的应用程

  • 我已经编写了一个php用户登录脚本,虽然我已经设法使注册页面正常工作(从而排除了common.php文件的内容是一个问题),并在mySQL中检查了数据库正在填充,但我似乎无法使登录本身发布任何内容,而不是不成功。 我肯定是在数据库中输入用户名和密码。有人能看出我哪里出了问题,或者建议我如何检查哪里出了问题吗? 表jmp_users的结构如下: 我的login.php页面是:

  • 问题内容: 我想要在spring成功注册后自动登录:我有一个受保护的页面,需要登录才能访问它们,我要在注册后跳过登录页面并进行自动登录,以便用户可以看到受保护的页面有我吗?我正在使用spring 3.0,spring security 3.0.2,该怎么做? 问题答案: 可以通过以下方式(半伪代码)通过spring安全性完成此操作: 更新:仅包含注册后如何创建会话

  • 我有一个Spring Boot应用程序,使用Spring Security和Keyclope作为IDP。 Keyclope在以下位置可用https://auth.example.com,具有一个具有客户端backo核心的领域backo和一个配置了所需角色的testuser。 如果我配置本地应用程序,请使用 一切正常。 如果我将其部署到我的开发环境中https://backo.example.com

  • 我正在用android编程。当我使用(LoginActivity)成功登录时,下一步是加载MainActivity,这个MainActivity是一个导航抽屉活动,但我遇到了这个错误: 致命异常:主进程:com.example.administrador.vicon,PID:32149java.lang.运行时异常:无法启动活动ComponentInfo{com.example.administr