当前位置: 首页 > news >正文

Java Web开发实战与项目——用户认证与授权模块开发

Web应用中,用户认证与授权是至关重要的功能,确保只有合法用户才能访问受保护的资源。Spring Security作为一个强大的安全框架,支持多种认证与授权方式。在本章节中,我们将深入探讨三种常见的用户认证与授权方案:基于Token的用户认证(JWT)、OAuth2认证与授权,以及使用Spring Security与OAuth2实现社交登录。


1. 实现基于Token的用户认证(JWT)
1.1 什么是JWT

JWT(JSON Web Token)是一种基于Token的认证机制,广泛应用于分布式系统中。它通常由三部分组成:

  • Header:通常包含Token类型和加密算法的信息。
  • Payload:包含用户的身份信息及相关的元数据(如角色)。
  • Signature:用于验证JWT的真实性,通常使用秘钥进行加密。

JWT的优势在于它是无状态的,也就是说,服务器不需要存储会话信息,所有信息都包含在JWT中。这使得它非常适用于微服务架构和分布式系统。

1.2 JWT认证流程
  1. 用户登录时,提交用户名和密码。
  2. 服务器验证用户信息,通过验证后生成JWT。
  3. 将JWT返回给客户端,客户端保存Token。
  4. 客户端在后续请求中,将Token附加在HTTP请求的Authorization头部中,服务器通过解密Token来验证用户身份。
1.3 使用Spring Boot实现JWT认证
  1. 添加依赖

pom.xml中添加JWT相关依赖:

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.11.5</version>
</dependency>

生成JWT的工具类

创建一个JWT生成工具类,用于生成和解析JWT。

@Component
public class JwtTokenUtil {

    private String secretKey = "secret";  // 秘钥,应该放在配置文件中

    private long expirationTime = 86400000L;  // 过期时间,24小时

    // 生成JWT
    public String generateToken(String username) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + expirationTime);

        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(now)
                .setExpiration(expiryDate)
                .signWith(SignatureAlgorithm.HS512, secretKey)
                .compact();
    }

    // 从JWT中解析出用户名
    public String getUsernameFromToken(String token) {
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(token)
                .getBody()
                .getSubject();
    }

    // 验证JWT是否有效
    public boolean validateToken(String token, String username) {
        String parsedUsername = getUsernameFromToken(token);
        return (parsedUsername.equals(username) && !isTokenExpired(token));
    }

    // 判断JWT是否过期
    private boolean isTokenExpired(String token) {
        Date expiration = Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(token)
                .getBody()
                .getExpiration();
        return expiration.before(new Date());
    }
}

认证过滤器

创建一个过滤器,用于在每个请求中验证JWT。

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        String token = request.getHeader("Authorization");

        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
            String username = jwtTokenUtil.getUsernameFromToken(token);

            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                UsernamePasswordAuthenticationToken authentication =
                        new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }

        filterChain.doFilter(request, response);
    }
}

​​​​​​​用户认证与生成Token

在用户登录时,生成JWT并返回给客户端。

@RestController
public class AuthController {

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @PostMapping("/login")
    public ResponseEntity<?> createAuthenticationToken(@RequestBody AuthenticationRequest authenticationRequest) {
        // 验证用户身份
        if ("user".equals(authenticationRequest.getUsername()) && "password".equals(authenticationRequest.getPassword())) {
            String token = jwtTokenUtil.generateToken(authenticationRequest.getUsername());
            return ResponseEntity.ok(new AuthenticationResponse(token));
        }
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid credentials");
    }
}
1.4 保护资源

在需要保护的资源上使用@PreAuthorize@Secured注解来进行权限控制。

@RestController
@RequestMapping("/admin")
public class AdminController {

    @GetMapping("/dashboard")
    @PreAuthorize("hasRole('ADMIN')")
    public String getAdminDashboard() {
        return "Admin Dashboard";
    }
}

2. 配置OAuth2认证与授权
2.1 什么是OAuth2

OAuth2是一个授权框架,用于让第三方应用访问用户资源而无需暴露用户的用户名和密码。OAuth2通过授权码密码客户端凭证等不同方式来获取Token,常见的应用场景包括社交登录和API访问。

2.2 配置OAuth2认证

在Spring Boot中,OAuth2认证可以通过spring-security-oauth2-clientspring-security-oauth2-jose等库来配置。

​​​​​​​添加依赖

pom.xml中添加OAuth2的相关依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

​​​​​​​配置application.yml

application.yml中配置OAuth2客户端信息,如以下示例配置Google OAuth2登录:

spring:
  security:
    oauth2:
      client:
        registration:
          google:
            client-id: YOUR_GOOGLE_CLIENT_ID
            client-secret: YOUR_GOOGLE_CLIENT_SECRET
            scope:
              - profile
              - email
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
            authorization-grant-type: authorization_code
            client-name: Google
        provider:
          google:
            authorization-uri: https://accounts.google.com/o/oauth2/auth
            token-uri: https://oauth2.googleapis.com/token
            user-info-uri: https://www.googleapis.com/oauth2/v3/userinfo

​​​​​​​OAuth2登录处理

Spring Boot自动处理OAuth2登录过程。您只需配置相关的OAuth2提供商(如Google、GitHub等),并在应用中使用@EnableOAuth2Sso注解来开启社交登录。

@SpringBootApplication
@EnableOAuth2Sso
public class OAuth2Application {

    public static void main(String[] args) {
        SpringApplication.run(OAuth2Application.class, args);
    }
}

3. 使用Spring Security与OAuth2实现社交登录
3.1 社交登录简介

社交登录(Social Login)是指通过已有的社交媒体账户(如Google、Facebook、GitHub等)进行身份验证的方式。通过OAuth2协议,用户无需在每个应用中注册单独的账户,只需使用现有的社交账户登录。

3.2 配置社交登录

​​​​​​​配置第三方OAuth2登录

以GitHub为例,在application.yml中配置GitHub OAuth2客户端:

spring:
  security:
    oauth2:
      client:
        registration:
          github:
            client-id: YOUR_GITHUB_CLIENT_ID
            client-secret: YOUR_GITHUB_CLIENT_SECRET
            scope: read:user
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
            authorization-grant-type: authorization_code
            client-name: GitHub
        provider:
          github:
            authorization-uri: https://github.com/login/oauth/authorize
            token-uri: https://github.com/login/oauth/access_token
            user-info-uri: https://api.github.com/user

​​​​​​​自定义用户信息

OAuth2UserService中,您可以自定义如何从OAuth2提供商获取用户信息。

@Service
public class CustomOAuth2UserService extends DefaultOAuth2UserService {

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        OAuth2User user = super.loadUser(userRequest);
        // 在此可以从user中获取用户信息并存储到数据库
        return user;
    }
}

​​​​​​​社交登录成功后的回调处理

使用Spring Security的默认OAuth2登录机制,用户登录成功后会自动跳转到指定的成功页面,您可以在SecurityConfig中自定义成功和失败的处理:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .oauth2Login()
                .loginPage("/login")
                .successHandler(new OAuth2LoginSuccessHandler())
                .failureHandler(new OAuth2LoginFailureHandler());
    }
}
3.3 完成社交登录

通过以上配置,您已经成功集成了OAuth2社交登录,支持用户通过Google、GitHub等社交账户进行登录。


总结

本文详细介绍了基于Token的用户认证(JWT)、OAuth2认证与授权的配置与实现,以及如何使用Spring Security与OAuth2实现社交登录。通过这些技术,我们可以实现灵活且安全的认证与授权机制,并有效地支持分布式应用和微服务架构中的用户管理。

关于作者:

15年互联网开发、带过10-20人的团队,多次帮助公司从0到1完成项目开发,在TX等大厂都工作过。当下为退役状态,写此篇文章属个人爱好。本人开发期间收集了很多开发课程等资料,需要可联系我

相关文章:

  • AlphaFold v3.0.1 conda版本详细安装与使用
  • Nginx 在Linux中安装、使用
  • order by 字段没有在 select distinct 中的问题
  • OpenMv识别色块通过串口发给STM32
  • vue3之echarts3D圆柱
  • share.py
  • Java集合之ArrayList(含源码解析 超详细)
  • python-leetcode 36.二叉树的最大深度
  • 使用vscode调试transformers源码
  • Linux中的Ctrl+C与Ctrl+Z
  • Docker 容器安装 Dify的两种方法
  • 审计级别未启用扩展模式导致查询 DBA_AUDIT_TRAIL 时 SQL_TEXT 列为空
  • Swupdate升级不强制依赖version字段
  • 装win10系统提示“windows无法安装到这个磁盘,选中的磁盘采用GPT分区形式”解决方法
  • DeepSeek 通过 ollama 轻松本地部署
  • LeetCode 热题 100_N 皇后 (62_51_困难_C++)(递归(回溯))
  • 【一文读懂】JS与Java的区别
  • 基于Python的Diango旅游数据分析推荐系统设计与实现+毕业论文(15000字)
  • Android 平台GB28181设备接入实战指南
  • day 19
  • 关于网站建设的可行性报告/营销模式有几种
  • 彩票网站怎么做ip管理/百度搜索的优势
  • php动态网站开发 网站成品/网页链接制作生成
  • 西安品牌网站建设服务商/近期时事新闻
  • 做外贸有哪些免费的网站有哪些/网络营销推广外包平台
  • 南京做网站建设有哪些内容/百度查重工具