首页IT科技webservice 服务注册(Web应用程序的身份验证:Session认证、Token认证)

webservice 服务注册(Web应用程序的身份验证:Session认证、Token认证)

时间2025-09-03 19:00:59分类IT科技浏览7256
导读:一、Web应用程序的身份验证...

一                、Web应用程序的身份验证

1                        、Session认证

① 用户向服务器发送用户名和密码

② 服务器验证通过后                ,在当前对话(session)里面保存相关数据                        ,如用户角色        ,登陆时间等

③ 服务器向用户返回一个session_id            ,写入用户的Cookie

④ 用户随后的每一次请求                        ,都会通过Cookie            ,将session_id传回服务器

⑤ 服务器收到session_id        ,找到前期保存的数据                        ,由此得知用户的身份

认证流程:

        Session认证的方式扩展性不好                ,如果是服务器集群    ,或者是跨域的服务导向架构                        ,就要求session数据共享                    ,以便每台服务器都能够读取session,针对这问题有两种解决方案:

        ① session数据持久化                    ,写入数据库或别的持久层                。优点是架构清晰                        ,但工程量大

        ② 服务器不再保存session数据    ,所有数据都保存在客户端                ,每次请求都发回服务器                        。Token就是其中一个代表

2        、Token认证

Token是在服务端产生的一串字符串                        ,是客户端访问资源接口(API)时所需要的资源凭证

        ① 客户端使用用户名和密码请求登陆        ,服务端收到请求            ,去验证用户名和密码

        ② 验证成功后                        ,服务端会签发一个token并把这个token发送给客户端

        ③ 客户端收到token后            ,存储起来        ,比如放在cookie或者localStorage里头

        ④ 客户端每次向服务端请求资源时需要带上这个token

        ⑤ 服务端收到请求后去验证这个token                        ,成功则返回请求数据

实现方式:JWT(JSON Web Token)认证

原理:

① 用户发送用户名和密码后                ,服务器认证并生成JWT令牌(JSON对象)    ,将其发回给客户端

 (为了防止用户篡改数据                        ,服务器在生成这个对象的时候会加上签名)

② 客户端将JWT令牌存储在本地以便后续使用

③ 当客户端向另一个域名服务器发送请求时                    ,将JWT令牌作为请求头(放在Authorization字段里头)或请求参数发送

④ 服务器收到请求后,检查JWT令牌的有效性                    ,并进行身份验证和授权

⑤ 若令牌有效则返回请求的数据                        ,否则返回未授权的错误信息

JWT由三个部分组成:

1            、Header(头部):

{  "alg": "HS256", // 令牌类型  "typ": "JWT" //加密算法 }

2                        、Payload(负载):

{ "iss": "example.com", "sub": "1234567890", "aud": ["foo", "bar"], "exp": 1648696800, "nbf": 1648693200, // 2022年4月29日10:20:00 "iat": 1648694700, "jti": "abcdef123456" } // 1            、iss(issuer): 表示JWT签发者的名称    ,通常是一个字符串或URL        。 // 2        、sub(subject): 表示JWT的主题                ,即客户端的唯一标识符                        ,通常是一个用户ID            。 // 3                        、aud(audience): 表示JWT的预期接收者        ,即对该JWT有效的接收方            ,可以是单个字符串或一个字符串数组                        。 // 4                、exp(expiration time): 表示JWT的过期时间                        ,用Unix时间戳表示            。 // 5    、nbf(not before): 表示JWT的生效时间            ,用Unix时间戳表示        。 // 6                        、iat(issued at): 表示JWT的签发时间        ,用Unix时间戳表示                        。 // 7                    、jti(JWT ID): 表示JWT的唯一标识符                        ,通常用于避免重放攻击                。

3、Signature(签名):由Header                    、Payload和一个密钥(secret                ,存储在服务器端    ,对外不可见)进行签名生成    。

HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

将Header                        、Payload和Signature通过.连接在一起形成JWT令牌                        ,例如:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

代码实现:

① 引入依赖

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

② 添加JWT配置

# JWT相关配置 jwt.secret=your-secret jwt.expiration=3600

③ 创建JWT工具类:用于生成和解析JWT

@Component public class JwtUtils { ​    // 秘钥    @Value("${jwt.secret}")    private String secret; ​    // 过期时间                    ,单位秒    @Value("${jwt.expiration}")    private Long expiration; ​    // 生成JWT    public String generateToken(Long userId) {        SecretKey key = Keys.hmacShaKeyFor(secret.getBytes()); // 创建密钥        Date now = new Date();        Date expireTime = new Date(now.getTime() + expiration * 1000);        return Jwts.builder()           .setIssuer("issuer") // 设置JWT的签发者           .setAudience("audience") // 设置JWT的接收方           .setSubject(userId.toString()) // 设置JWT的主题           .setIssuedAt(now) // 设置JWT的签发时间           .setExpiration(expireTime) // 设置JWT的过期时间           .signWith(key, SignatureAlgorithm.HS256) // 用HS256算法和密钥key签名JWT           .compact(); // 生成JWT字符串   } ​    // 解析JWT    public Claims parseToken(String token) {        SecretKey key = Keys.hmacShaKeyFor(secret.getBytes()); // 创建密钥        return Jwts.parserBuilder()               .setSigningKey(key) // 设置用于解析JWT的密钥               .build()               .parseClaimsJws(token) // 解析JWT,获取Jws<Claims>实例               .getBody();   } }

④ 配置拦截器:用于验证请求中的JWT是否有效

@Component public class JwtInterceptor implements HandlerInterceptor { ​    @Autowired    private JwtUtils jwtUtils; ​    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {        // 从请求头中获取token        String token = request.getHeader("Authorization");        // 判断token是否存在并以Bearer开头        if (token != null && token.startsWith("Bearer ")) {            token = token.substring(7); // 去掉token前缀            Claims claims = jwtUtils.parseToken(token); // 解析JWT            if (claims != null) {                Long userId = Long.valueOf(claims.getSubject()); // 获取JWT中的用户id                // 将用户信息存储到request中                    ,方便后续操作                request.setAttribute("userId", userId);                return true;           }       }        // 解析失败                        ,返回401未授权状态码        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);        return false; // 拦截请求   } } ​

⑤ 使用JWT

@RestController @RequestMapping("/api") public class UserController {        @Autowired    private UserService userService;     @PostMapping("/login") public ResponseEntity<?> login(@RequestBody UserLoginDto userLoginDto) {   // 用户登录逻辑       // 生成 JWT token   String token = Jwts.builder()           .setSubject(user.getUsername()) // 主题           .claim("roles", user.getRoles())           .setIssuedAt(new Date()) // 签发时间           .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) // 过期时间           .signWith(SignatureAlgorithm.HS512, SECRET_KEY) // 使用算法和密钥对token进行签名                        。           .compact(); // 将JWT token生成为字符串       // 返回 token 给客户端   return ResponseEntity.ok(new AuthResponse(token)); } ​     @GetMapping("/users") @PreAuthorize("hasAuthority(ROLE_ADMIN)") // 拥有 ROLE_ADMIN 权限的用户才能访问该方法 public ResponseEntity<?> getUsers(@RequestHeader("Authorization") String authorizationHeader) {        String token = authorizationHeader.substring(7); // 去掉 "Bearer" 前缀            // 验证 token 是否有效        Claims claims = Jwts.parser() // 获取一个JwtParser对象         .setSigningKey(SECRET_KEY) // 设置JWT的签名密钥    ,用于校验JWT的合法性         .parseClaimsJws(token) // 将其转化为Jws对象           .getBody(); // 获取Jws对象中的payload信息          // 获取用户列表逻辑 } ​        @GetMapping("/users/{id}")    public ResponseEntity<?> getUserById(@PathVariable Long id) {        // 根据用户ID获取用户信息逻辑   }        // 省略其他接口... }

Session和Token认证的区别:

        Session和Token都是常用的用户认证方式                ,它们的作用都是为了验证用户身份和授权访问资源                        ,但是它们的实现方式有所不同                    。

        Session是一种服务器端认证方式        ,通常通过在服务器端保存用户的登录信息(较安全)            ,以便在后续的请求中进行验证。当用户进行登录操作时                        ,服务器会创建一个Session            ,并给这个Session分配一个唯一的标识符(Session ID)        ,然后将这个Session ID发送给客户端保存                    。客户端在后续的请求中需要携带这个Session ID                        ,服务器端根据这个Session ID来查找对应的Session                ,从而验证用户的身份                        。

        Token是一种无状态认证方式    ,通常通过在客户端保存用户的登录信息(不安全)                        ,以便在后续的请求中进行验证    。当用户进行登录操作时                    ,服务器会生成一个Token,并将这个Token发送给客户端保存                。客户端在后续的请求中需要携带这个Token                    ,服务器端通过验证这个Token来确定用户的身份                        。

优缺点:

        Session需要在服务器端保存用户的登录信息                        ,因此需要占用服务器的资源    ,并且需要在分布式系统中进行Session共享和Session失效管理(工程量大)        。

        Token是无状态的                ,不需要在服务器端保存用户的登录信息                        ,因此具有良好的可扩展性        ,并且可以很方便地实现分布式系统中的认证和授权            。用解析token的计算时间换取session的存储空间            ,从而减轻服务器压力                        ,减少频繁查询数据库

        Session的安全性比较高            ,因为Session的内容保存在服务器端        ,客户端无法直接修改Session的内容

        Token的安全性相对较低                        ,因为Token的内容保存在客户端                ,客户端可以通过一些手段来篡改Token的内容                        。

Session和Token的应用场景:

        一般来说    ,使用 session 可能更适合传统的 Web 应用                        ,因为它通常需要用户在浏览器中持续地与应用交互                    ,而且涉及到敏感数据的处理            。例如,在电子商务网站中                    ,用户需要登录才能访问个人购物车和订单等敏感信息                        ,此时可以使用 session 来验证用户身份    ,并在服务器端存储相关的用户信息和状态        。

        而在 API (应用程序编程接口)设计和单页面应用中                ,使用 token 可能更加常见                        。由于 API 和单页面应用的特性                        ,客户端可以直接与 API 或后端服务通信        ,而不需要经过浏览器的中间层                。此时            ,使用 token 可以避免一些 session 的问题                        ,如跨域和服务器负载均衡等    。同时            ,token 也更容易在不同服务之间进行传递和共享        ,比如使用 OAuth2 等协议来实现单点登录和授权等功能                        。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
注意力机制介绍(注意力机制详解) 如何进行网站SEO布局(轻松让你的网站排名更优)