jxjxjdjdjd 2024-04-27 13:50 采纳率: 50%
浏览 6
已结题

Spring Security登录问题

我们系统是Spring Security,然后要跟第三方对接统一登录,用的aouth2授权模式,我们这边只做回调处理.
授权服务器跳转到我们系统之后,进行账号校验存在的话,直接进入系统吗?如果直接进入系统,redis中的token又是怎样存进去的?
我想的是我们系统内部应该要再登录一次,然后登录的话,需要账号密码,但是拿不到密码.只能新写一个登录接口,只需要账号就能登录.
新写登录接口,还得用Spring Security原有的登录逻辑,原来的登录和新的登录需要并存,目前情况就是这样,各位有没有什么思路

  • 写回答

4条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-04-27 13:50
    关注

    引自免费微信小程序:皆我百晓生

    在Spring Security中实现OAuth2的集成,并且需要支持账号校验和令牌存储,我们可以按照以下步骤进行操作。

    1. 配置OAuth2客户端

    首先,你需要配置OAuth2客户端,这通常在application.ymlapplication.properties文件中完成。例如:

    spring:
      security:
        oauth2:
          client:
            registration:
              third_party:
                clientId: your_client_id
                clientSecret: your_client_secret
                provider: third_party_provider
                redirectUriTemplate: "{baseUrl}/login/oauth2/code/{registrationId}"
            provider:
              third_party_provider:
                authorization-uri: https://third-party.com/oauth/authorize
                token-uri: https://third-party.com/oauth/token
                user-info-uri: https://third-party.com/userinfo
                jwk-set-uri: https://third-party.com/jwks
    
    1. 添加必要的依赖

    确保你的项目包含以下依赖项(如果你还没有添加):

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.security.oauth.boot</groupId>
        <artifactId>spring-security-oauth2-autoconfigure</artifactId>
    </dependency>
    
    1. 实现OAuth2登录回调处理

    创建一个控制器来处理OAuth2的回调请求。在这个控制器里,你会从OAuth2提供商那里获取用户信息并验证它。

    @Controller
    public class OAuth2CallbackController {
    
        @Autowired
        private UserDetailsService userDetailsService;
    
        @Autowired
        private AuthenticationManager authenticationManager;
    
        @RequestMapping(value = "/login/oauth2/code/{registrationId}")
        public String processAuthorizationCode(
            @PathVariable("registrationId") String registrationId,
            RedirectAttributes attributes,
            OAuth2AuthenticationToken auth) {
            
            // 获取用户信息
            Principal principal = auth.getUserAuthentication().getPrincipal();
            // 根据principal获取UserDetails对象
            UserDetails userDetails = userDetailsService.loadUserByUsername(principal.getName());
    
            // 使用Spring Security的登录逻辑进行登录
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            try {
                authenticationManager.authenticate(token);
            } catch (AuthenticationException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
    
            SecurityContextHolder.getContext().setAuthentication(token);
    
            // 将用户信息保存到Redis
            saveTokenToRedis(userDetails, auth);
    
            return "redirect:/"; // 返回应用首页
        }
    
        private void saveTokenToRedis(UserDetails userDetails, OAuth2AuthenticationToken auth) {
            // 这里是一个示例,实际操作可能需要根据你的Redis配置进行调整
            RedisTemplate<String, OAuth2AccessToken> redisTemplate = new StringRedisTemplate();
            String key = "user:" + userDetails.getUsername();
            redisTemplate.opsForValue().set(key, auth.getAccessToken().getValue());
        }
    }
    
    1. 自定义登录接口

    为了支持仅凭用户名登录,你需要创建一个新的登录接口。这里可以使用JWT作为令牌,因为OAuth2本身已经处理了大部分安全方面的工作。

    @RestController
    @RequestMapping("/api/login")
    public class CustomLoginController {
    
        @Autowired
        private UserRepository userRepository;
        
        @Autowired
        private JwtService jwtService;
    
        @PostMapping("/username")
        public ResponseEntity<?> login(@RequestBody LoginRequest request) {
            User user = userRepository.findByUsername(request.getUsername());
            if (user == null || !passwordEncoder().matches(request.getPassword(), user.getPassword())) {
                throw new ResourceNotFoundException("Invalid credentials");
            }
    
            // 生成JWT令牌
            String accessToken = jwtService.generateToken(user);
            
            // 返回响应体
            return ResponseEntity.ok(new JwtResponse(accessToken));
        }
    }
    
    // 响应模型类
    class JwtResponse {
        private final String accessToken;
    
        public JwtResponse(String accessToken) {
            this.accessToken = accessToken;
        }
    
        // getters and setters
    }
    
    // 请求模型类
    class LoginRequest {
        private String username;
        private String password;
    
        // getters and setters
    }
    
    1. Spring Security配置

    确保Spring Security配置正确地处理了这些端点和认证过程。在你的SecurityConfig.java中,添加以下内容:

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private CustomAuthenticationProvider customAuthenticationProvider;
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                .antMatchers("/login/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .oauth2Login()
                .redirectionEndpointrediRectUriTemplate("/{registrationId}/callback")
                .and()
                .logout().logoutSuccessUrl("/")
                .and()
                .csrf().disable(); // 如果使用JWT,可能需要禁用CSRF保护
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.authenticationProvider(customAuthenticationProvider);
        }
    }
    
    1. 自定义AuthenticationProvider

    创建一个自定义的AuthenticationProvider,以便在调用customAuthenticationProvider.authenticate()时,使用CustomLoginController提供的用户名登录功能。

    @Service
    public class CustomAuthenticationProvider implements AuthenticationProvider {
    
        @Autowired
        private UserRepository userRepository;
    
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            String name = authentication.getName();
            String password = authentication.getCredentials().toString();
    
            User user = userRepository.findByUsername(name);
            if (user != null && passwordEncoder().matches(password, user.getPassword())) {
                return new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities());
            }
    
            throw new BadCredentialsException("Invalid credentials");
        }
    
        @Override
        public boolean supports(Class<?> authentication) {
            return authentication.equals(UsernamePasswordAuthenticationToken.class);
        }
    }
    

    以上代码示例展示了如何实现OAuth2登录与基于用户名的登录功能。你可能需要根据实际情况对代码进行一些调整,比如数据库访问、加密方法等。同时,确保你的Redis服务器已启动,并且连接配置正确。

    本回答被专家选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(3条)

报告相同问题?

问题事件

  • 系统已结题 5月13日
  • 专家已采纳回答 5月5日
  • 创建了问题 4月27日

悬赏问题

  • ¥15 llama3中文版微调
  • ¥15 时间序列预测算法 预测结果出现负值
  • ¥15 在win系统Django虚拟环境下载mysqlclient报错
  • ¥15 pg数据库导入数据序列重复
  • ¥15 三分类机器学习模型可视化分析
  • ¥15 本地测试网站127.0.0.1 已拒绝连接,如何解决?(标签-ubuntu)
  • ¥50 Qt在release捕获异常并跟踪堆栈(有Demo,跑一下环境再回答)
  • ¥30 python,LLM 文本提炼
  • ¥15 关于将inet引入的相关问题
  • ¥15 关于一个倒计时的操作和显示设计