实战3 认证成功返回token和用户授权

文章讲述了使用SpringBoot和JWT进行用户认证,包括生成和验证token、设置过期时间,以及在成功认证后返回token的过程,还涉及用户授权和权限管理的相关操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、认证成功返回token

1、什么是token

2、token认证流程图​编辑

3、认证成功处理器返回token信息

二、用户授权

1、修改Permission实体类

2、编写PermissionMapper接口 ​编辑

​3、编写PermissionMapper.xml映射文件

4、编写PermissionService接口

5、编写PermissionService接口实现  

6、User类添加权限菜单集合

​7、修改CustomerUserDetailsService类


一、认证成功返回token

1、什么是token

2、token认证流程图

 3 认证成功处理器返回token信息

(1)封装token返回的数据信息

package com.cizhu.utils;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class LoginResult {
    //用户编码
    private Long id;
    //状态码
    private int code;
    //token令牌
    private String token;
    //token过期时间
    private Long expireTime;
}

(2)编写token工具类

package com.cizhu.utils;

import com.cizhu.entity.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Data
@ConfigurationProperties(prefix = "jwt")
@Component
public class JwtUtils {
    //密钥
    private String secret;
    // 过期时间 毫秒
    private Long expiration;

    /**
     * 从数据声明生成令牌
     *
     * @param claims 数据声明
     * @return 令牌
     */
    private String generateToken(Map<String, Object> claims) {
        Date expirationDate = new Date(System.currentTimeMillis() + expiration);
        return Jwts.builder().setClaims(claims).setExpiration(expirationDate).signWith(
                SignatureAlgorithm.HS512, secret).compact();
    }

    /**
     * 从令牌中获取数据声明
     *
     * @param token 令牌
     * @return 数据声明
     */
    public Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims =
                    Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }

    /**
     * 生成令牌
     *
     * @param userDetails 用户
     * @return 令牌
     */
    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(Claims.SUBJECT, userDetails.getUsername());
        claims.put(Claims.ISSUED_AT, new Date());
        return generateToken(claims);
    }

    /**
     * 从令牌中获取用户名
     *
     * @param token 令牌
     * @return 用户名
     */
    public String getUsernameFromToken(String token) {
        String username;
        try {
            Claims claims = getClaimsFromToken(token);
            username = claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    /**
     * ()编写全局配置文件
     * 在application.properties全局配置文件中自定义jwt属性。
     * ()认证成功处理器类返回token数据
     * 在原有的LoginSuccessHandler登录认证成功处理器类上加入jwt相关代码。
     * 注意:在原有的基础上添加下面第~行的代码。
     * 判断令牌是否过期
     *
     * @param token 令牌
     * @return 是否过期
     */
    public Boolean isTokenExpired(String token) {
        Claims claims = getClaimsFromToken(token);
        Date expiration = claims.getExpiration();
        return expiration.before(new Date());
    }

    /**
     * 刷新令牌
     *
     * @param token 原令牌
     * @return 新令牌
     */
    public String refreshToken(String token) {
        String refreshedToken;
        try {
            Claims claims = getClaimsFromToken(token);
            claims.put(Claims.ISSUED_AT, new Date());
            refreshedToken = generateToken(claims);
        } catch (Exception e) {
            refreshedToken = null;
        }
        return refreshedToken;
    }

    /**
     * 验证令牌
     *
     * @param token       令牌
     * @param userDetails 用户
     * @return 是否有效
     */
    public Boolean validateToken(String token, UserDetails userDetails) {
        User user = (User) userDetails;
        String username = getUsernameFromToken(token);
        return (username.equals(user.getUsername()) && !isTokenExpired(token));
    }
}

package com.cizhu.config.security.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.cizhu.entity.User;
import com.cizhu.utils.JwtUtils;
import com.cizhu.utils.LoginResult;
import com.cizhu.utils.ResultCode;
import io.jsonwebtoken.Jwts;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * 认证成功处理器
 */

@Component
public class LoginSuccessHandler implements AuthenticationSuccessHandler {
    @Resource
    private JwtUtils jwtUtils;
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        //设置响应编码格式
        response.setContentType("applicaiton/json;charset=utf-8");
        //换取当前登录用户信息
        User user = (User)authentication.getPrincipal();
        //生成token
        String token = jwtUtils.generateToken(user);
        //设置token签名密钥及过期时间
        long expireTime = Jwts.parser() //获取DefaultJwtParser对象
                .setSigningKey(jwtUtils.getSecret()) //设置签名的密钥
                .parseClaimsJws(token.replace("jwt_", ""))
                .getBody().getExpiration().getTime();//获取token过期时间
        //创建登录结果对象
        LoginResult loginResult = new LoginResult(user.getId(),
                ResultCode.SUCCESS,token,expireTime);
        //将对象转换成JSON格式,并消除循环引用
        String result = JSON.toJSONString(user, SerializerFeature.DisableCircularReferenceDetect);
        //获取输出流
        ServletOutputStream outputStream = response.getOutputStream();
        outputStream.write(result.getBytes(StandardCharsets.UTF_8));
        outputStream.flush();
        outputStream.close();
    }
}

二、用户授权

 1、修改Permission实体类

2、编写PermissionMapper接口 

 3  编写PermissionMapper.xml映射文件

<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.youmans.authority.entity.Permission">
    <id column="id" property="id"/>
    <result column="label" property="label"/>
    <result column="parent_id" property="parentId"/>
    <result column="parent_name" property="parentName"/>
    <result column="code" property="code"/>
    <result column="path" property="path"/>
    <result column="name" property="name"/>
    <result column="url" property="url"/>
    <result column="type" property="type"/>
    <result column="icon" property="icon"/>
    <result column="create_time" property="createTime"/>
    <result column="update_time" property="updateTime"/>
    <result column="remark" property="remark"/>
    <result column="order_num" property="orderNum"/>
    <result column="is_delete" property="isDelete"/>
</resultMap>

<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
    id, label, parent_id, parent_name, code, path, name, url, type, icon, create_time, update_time, remark, order_num, is_delete
</sql>
<select id="findPermissionListByUserId" resultType="com.youmans.authority.entity.Permission">
    select
        DISTINCT
        p.id,p.parent_id,p.label,p.`code`,p.url,p.type,p.icon,p.remark,p.path,p.name
    from
        sys_user as u
            left join sys_user_role as ur on u.id = ur.user_id
            left join sys_role as r on ur.role_id = r.id
            left join sys_role_permission as rp on rp.role_id = r.id
            left join sys_permission as p on rp.permission_id = p.id
    where u.id =#{userId}
    order by p.id asc
</select>

4 编写PermissionService接口

5 编写PermissionService接口实现  

6、User类添加权限菜单集合

 7、修改CustomerUserDetailsService类

在CustomerUserDetailsService类原有的基础上添加相应的用户授权代码

package com.cizhu.config.security.service;

import com.cizhu.entity.Permission;
import com.cizhu.entity.User;
import com.cizhu.mapper.PermissionMapper;
import com.cizhu.service.IPermissionService;
import com.cizhu.service.IUserService;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 用户认证处理器类
 */
@Component
public class CustomerUserDetailsService implements UserDetailsService {
    @Resource
    private IUserService userService;

    @Resource
    private IPermissionService permissionService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //调用根据用户名查询用户信息的方法
        User user = userService.findUserByUserName(username);
        if (user ==null){
            throw new UsernameNotFoundException("用户名或密码错误");
        }
        //查询当前用户拥有的权限列表
        List<Permission> permissionList = permissionService.findPermissionListByUserId(user.getId());
        //获取对应的权限编码
        List<String> codeList = permissionList.stream()
                .filter(Objects::nonNull)
                .map(item -> item.getCode())
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        //将权限编码列表转换成数组
        String[] strings= codeList.toArray(new String[codeList.size()]);
        //设置权限列表
        List<GrantedAuthority> authorityList= AuthorityUtils.createAuthorityList(strings);
        //将权限列表设置给user对象
        user.setAuthorities(authorityList);
        //设置该用户拥有的菜单信息
        user.setPermissionList(permissionList);
        return user;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值