# String-security(配置异常处理器,封装JWT工具类)

news2024/12/23 0:37:52

1 JWT是做什么的?

为了在前后端分离项目中使用 JWT ,我们需要达到 2 个目标:

  • 在用户登录认证成功后,需要返回一个含有 JWT token 的 json 串。

  • 在用户发起的请求中,如果携带了正确合法的 JWT token ,后台需要放行,运行它对当前 URI 的访问

在spring security项目中添加nimbus坐标即可

  <!--nimbus坐标-->
<dependency>
    <groupId>com.nimbusds</groupId>
    <artifactId>nimbus-jose-jwt</artifactId>
    <version>9.11.1</version>
</dependency>

2 1、返回 JWT token

Spring Security 中的登录认证功能是由 UsernamePasswordAuthenticationFilter 完成的,默认情况下,在登陆成功后,接下来就是页面跳转,显示你原本想要访问的 URI( 或 / ),现在,我们需要返回 JSON(其中还要包含 JWT token )。

Spring Security 支持通过实现 AuthenticationSuccessHandler 接口,来自定义在登陆成功之后你所要做的事情(之前有讲过这部分内容):

http.formLogin()
    .successHandler(new JWTAuthenticationSuccessHandler());

当用户登录成功后,Spring security返回一个jwt的token给客户端,所以要在Spring security登录成功的过滤器中实现jwt token的生成代码。

  • 创建spring security项目并添加nimbus坐标

    关键坐标如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.woniu</groupId>
    <artifactId>spring-security-jwt</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.5.4</version>
    </parent>

    <dependencies>
        <!--springmvc启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--测试启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <!--springboot整合security坐标-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <!--nimbus坐标-->
        <dependency>
            <groupId>com.nimbusds</groupId>
            <artifactId>nimbus-jose-jwt</artifactId>
            <version>9.11.1</version>
        </dependency>
    </dependencies>
</project>

配置认证UserDetailsService

/**
 * spring security认证业务类
 */
@Service
public class LoginUserDetailsService implements UserDetailsService {
    @Resource
    private UserDao userDao;
    //为passwordEncoder注入值
    @Resource
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //调用dao到数据库中根据username查找用户信息
        Users users = userDao.getByUserName(username);
        try {
            //将查找到的用户帐号与密码保存到Security的User对象中由Security进行比对
            return new User(users.getUsername(), users.getPassword(),
                    AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER,user:insert,user:delete")); //配置登录用户有哪些角色和权限,此处模拟直接写死
        }catch (Exception e){
            throw  new UsernameNotFoundException("用户"+username+"不存在");
        }
    }
}

spring security配置类

package com.example.springsecurity3.configuration;

import com.example.springsecurity3.hndler.*;
import com.example.springsecurity3.service.SecurityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class UsersConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private SecurityService securityService;

        @Bean
        public PasswordEncoder getPassword(){
            return new BCryptPasswordEncoder();
        }

    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            //给密码加密
        auth.userDetailsService(securityService).passwordEncoder(getPassword());
    }

    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin().//告诉security,要是用自己的页面
                loginPage("/login.html").//告诉security页面在哪里
                loginProcessingUrl("/dologin").//告诉security表但提交地址(
                //hasAuthority,hasAnyAuthority,hasRole,hasAnyRole四种方法可以设置访问路径,现在我们用PreAuthorize("hasAuthority('admin')")注解就可以替我们
                //访问获取授权,在UserConfig类上加上EnableGlobalMethodSecurity(securedEnabled=true,proPostEnable=true)
              //注册登录成功处理器
               successHandler(new SecurityHandler()).
                //注册登录失败处理器
                failureHandler(new LoginFailHandler()).
                permitAll();//将登陆的权限放出来
        //注册未登录处理器,
        http.exceptionHandling().authenticationEntryPoint(new MyAuthenticationEntryPoint())
                //注册有用户名和密码,没有授权的处理器
                .accessDeniedHandler(new MyAccessDeniedHandler());
        //开启访问权限
        http.cors();
        //注册退出
        http.logout().logoutSuccessHandler(new LogoutSuccess());
        //配置权限请求
//        http.authorizeRequests().anyRequest().authenticated();//关闭所有请求
//        http.csrf().disable();//关闭跨站脚本攻击
        //配置权限请求
        http.authorizeRequests().
                anyRequest().
                authenticated();//关闭所有请求
        http.csrf().disable();//关闭跨站脚本攻击
    }
}

配置登录结果异常处理器

登录成功
package com.example.springsecurity3.hndler;

import com.alibaba.fastjson.JSON;
import com.example.springsecurity3.utils.JWTUtils;
import com.example.springsecurity3.utils.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 登录成功提示信息
 */
public class SecurityHandler implements AuthenticationSuccessHandler {
    @Autowired
    private RedisTemplate<String,String> redisTemplate;



    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        User user = (User) authentication.getPrincipal();
        //把jwt放入redis,并设置有效时间
//        try {
//            redisTemplate.opsForValue().set("jwt:"+user.getUsername(),
//                    JWTUtils.createJWT(user.getUsername()));
           // redisTemplate.opsForValue().set("jwt:"+user.getUsername(),JWTUtils.createJWT(user.getUsername()));
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
        System.out.println(user.getUsername());
        response.setContentType("application/json;charset=utf-8");
        PrintWriter pw = response.getWriter();
            //将json转成字符串
        String json = JSON.toJSONString(ResponseResult.SECCUSS);
        pw.print(json);
        pw.flush();
        pw.close();
    }

    }


在这里插入图片描述

登录失败
package com.example.springsecurity3.hndler;

import com.alibaba.fastjson.JSON;
import com.example.springsecurity3.utils.ResponseResult;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 登陆失败,后提示信息
 */
public class LoginFailHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        PrintWriter pw = response.getWriter();

        String json = JSON.toJSONString(ResponseResult.FAIL );
        pw.print(json);
        pw.flush();
        pw.close();
    }
}

在这里插入图片描述

未登录访问时,提示请先登录
package com.example.springsecurity3.hndler;

import com.alibaba.fastjson.JSON;
import com.example.springsecurity3.utils.ResponseResult;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 前后端分离项目,用户未登录直接访问系统资源,会被该类拦截
 */
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        PrintWriter pw = response.getWriter();

        String json = JSON.toJSONString(ResponseResult.NOTLOGIN );
        pw.print(json);
        pw.flush();
        pw.close();
    }
}

在这里插入图片描述

有用户名和密码,没有权限时提示请联系管理员
package com.example.springsecurity3.hndler;

import com.alibaba.fastjson.JSON;
import com.example.springsecurity3.utils.ResponseResult;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 虽然知道用户名和密码,但是你没有权限访问就会拦截呢没有权限的访问操作
 */
public class MyAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        PrintWriter pw = response.getWriter();

        String json = JSON.toJSONString(ResponseResult.NOTAUTH );
        pw.print(json);
        pw.flush();
        pw.close();
    }
}

在这里插入图片描述

退出成功提示
package com.example.springsecurity3.hndler;

import com.alibaba.fastjson.JSON;
import com.example.springsecurity3.utils.ResponseResult;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 用户退出操作
 */
public class LogoutSuccess implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        PrintWriter pw = response.getWriter();

        String json = JSON.toJSONString(ResponseResult.LOGOUT );
        pw.print(json);
        pw.flush();
        pw.close();
    }
}

在这里插入图片描述

创建JWT工具类

package com.example.springsecurity3.utils;

import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import org.springframework.beans.factory.SmartInitializingSingleton;

import java.text.ParseException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

/**
 * jet工具类
 * 1:创建jwt
 * 2:校验jwt是否合法
 * 3:返回载荷部分
 */
public class JWTUtils {


  public  static final  String KEY="adbaobcabcnpncinnpcnpnpnc";
  //随机生成32位的字符串
  //public static final String KEY=UUID.randomUUID().toString

     public static  String createJWT(String username)throws Exception{
         //创建JWT头部
         JWSHeader jwsHeader=new JWSHeader.
                 Builder(JWSAlgorithm.EdDSA.HS256).
                 type(JOSEObjectType.JWT).build();
         //创建载荷,储存用户信息
         Map  map=new  HashMap<>();
        map.put("username",username);
         Payload payload = new Payload(map);

         MACSigner jwsSigner = new MACSigner(KEY);
         //3.2创建类将头部和载荷加在一起组成新的字符串
         JWSObject jwsObject=new JWSObject(jwsHeader,payload);
         //3.3根据秘钥将jwsObject加密
        jwsObject.sign(jwsSigner);
        return  jwsObject.serialize();
     }

    /**
     * 接收用户传入的jwt字符串,根据秘钥进行解码,对比用户传入的jwt是正确的
     * 第一步:从页面拿到jwt字符串
     * 第二部:将jwt字符串成一个对象
     * 第三步:调用verify()方法,传一个秘钥看看能不能解析出来
     * JSON.parseObject 将字符串转成对象 JSON.toJSONString 将对象转成字符串
     * @param jwt
     * @return
     * @throws Exception
     */
     public static boolean getDecrypt (String jwt)throws Exception{


         //把jwt字符串转成jwt对象
         JWSObject jwsObject = JWSObject.parse(jwt);
         //把jwt对象通过秘钥解密
         MACVerifier macVerifier = new MACVerifier(KEY);
         //解密
         boolean verify = jwsObject.verify(macVerifier);
         return verify;

     }

    /**
     * 获取载荷内容
     * @param jwt
     * @return
     * @throws Exception
     */
    public  static Map getAccount(String jwt) throws Exception {
        //获取jet对象
        JWSObject parse = JWSObject.parse(jwt);
        //获取用户信息
        return  parse.getPayload().toJSONObject();

    }
}

登录成功使用redis数据库储存用户信息

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/77973.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ELK日志分析系统

目录 一.ELK概述 1.1 ELK简介 1.2 ELK日志组件 1.2.1 ELK组件介绍 1.3 日志处理步骤 二. Elasticsearch 集群部署 2.1 关闭防火墙 ​2.2 ELK Elasticsearch 集群部署&#xff08;在Node1&#xff0c;Node2节点上操作&#xff09; ​ 2.2.1 更改主机名​ 2.2.2 配置域名…

RCE漏洞简介

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是RCE漏洞简介。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xff1a;严禁对未授权设备进行…

高级篇之如何升级5GCPE固件

高级篇之如何升级5GCPE固件1. 准备工作2. 安装5GCPE串口驱动3. 升级固件3.1 选择固件3.2 选择串口号3.3 下载固件3.4 下载固件意外情况4. 重新启动结束&#xff01;LINKPI-5GCPE是LINKPI推出的可以做户外移动直播的 5G无线网关&#xff0c;可以支持三种模式&#xff1a; 网卡模…

计算机网络-分组交换与电路交换

有志者&#xff0c;事竟成 文章持续更新&#xff0c;可以关注【小奇JAVA面试】第一时间阅读&#xff0c;回复【资料】获取福利&#xff0c;回复【项目】获取项目源码&#xff0c;回复【简历模板】获取简历模板&#xff0c;回复【学习路线图】获取学习路线图。 文章目录一、分组…

普乐蛙VR航天科技馆太空体验馆VR太空舱体验馆vr飞碟遨游太空

什么是航天航空主题馆 普乐蛙VR航天航空体验馆系列 普乐蛙VR航天航空主题馆可以根据客户的需求&#xff0c;用航天航空的科技氛围方案进行布置&#xff0c;大多用最新的黑科技&#xff0c;让整个馆充满科技科幻的感觉&#xff0c;使人沉浸&#xff0c;容易进入主题。馆内设置不…

MySQL函数:列转行CONCAT、CONCAT_WS、GROUP_CONCAT的使用(精要)

前言 很久没有接触Mysql了。 今天心血来潮&#xff0c;突然想了解一下Mysql列转行&#xff0c;看了一些文章&#xff0c;重点不清晰&#xff0c;遂有下文&#xff01; Mysql官网、 社区版下载&#xff08; Windows版_mysql.8.0.31下载 &#xff09; 概述 Mysql内部提供了列转…

UNIAPP实战项目笔记50 登录和注册页面的布局

UNIAPP实战项目笔记50 登录和注册页面的布局 实际案例图片 登录页面布局 注册页面布局 显示登录和注册页面布局 页面布局的切换 具体内容图片自己替换哈&#xff0c;随便找了个图片的做示例 具体位置见目录结构 完善布局页面和样式 代码 login.vue部分 <template><v…

拉线援(AD PADS Cadence快捷键汇总)

年纪越大&#xff0c;记性就不太好了&#xff0c; 要干的活越多&#xff0c; 还要盯盘&#xff0c; 效率得提升一下。 总结下平时拉线容易用到的快捷键、评审资料等。 以后不断更新完善。 公众号发消息&#xff08;Download|拉线援&#xff09;可获得源文档。 一、Altium Desi…

水文气象站远程监测物联网系统,彰显水利治理智慧

我国在几千年的历史中都对水利设施建设十分重视&#xff0c;修建了各种类型的水利设施&#xff0c;在古代的生活、农业生产、防洪排水、漕运等多个方面发挥着非常重要的作用&#xff0c;如都江堰、郑国渠、坎儿井等设施更是青史留名。 到了现代&#xff0c;水资源治理依旧是民生…

开源SCRM营销平台-MarketGo产品介绍(二)

1、MarketGo概述 MarketGo中国式营销自动化开源项目标杆。 MarketGo更像是一个 SDK 、引擎&#xff0c;通过提供的标准化功能和基础能力&#xff0c;让开发者能快速搭建一个营销自动化系统&#xff0c;快速完成从0-1的过程&#xff0c;并且能基于开放的能力和源码&#xff0c…

爱了、阿里巴巴 JAVA 岗发布,最新内部面试题(含 P5-P7)

不少人对阿里巴巴技术岗的体系结构及级别的技术要求设置不太清楚&#xff0c;想去面试心里没底&#xff0c;下面简单介绍一下阿里 P5-P7 技术岗要求体系以及为大家分享一份涵盖阿里巴巴 P5-P7 的完整面试题&#xff01; 阿里 P5(高级研发工程师) 工作要求&#xff1a; 能独立…

容器的常用方法和线程安全(Map、List、Queue)

一、Map 1. HashTable 线程安全的Map&#xff0c;用synchronized锁 2. Collections.synchronizedMap Collections.synchronizedMap(new HashMap()) 可以把HashMap变成线程安全的&#xff0c;锁粒度比HashTable稍微小一点 3. ConcurrentHashMap ConcurrentHashMap主要提高…

【C++】STL - vector使用和模拟实现

&#x1f431;作者&#xff1a;傻响 &#x1f431;专栏&#xff1a;《C/C - STL》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; ​ 目录 No.1.vector的介绍及使用 1.1 vector的介绍 1.2 vector的接口 vector的构造函数接口 vector的…

最近很火的电视剧《点燃我,温暖你》男主角学神和女主角课代表计算机考试实现的跳动的爱心,全程用代码复原真实的实现

最近很火的电视剧《点燃我&#xff0c;温暖你》男主角学神和女主角课代表计算机考试实现的跳动的爱心&#xff0c;全程用代码复原真实的实现。 学神考试100分&#xff0c;只是因为试卷只有100分&#xff01; 该剧改编自作家Twentine创作的小说《打火机与公主裙》&#xff0c;讲…

微服务框架 SpringCloud微服务架构 微服务保护 31 限流规则 31.5 流控效果【排队等待】

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 微服务保护 文章目录微服务框架微服务保护31 限流规则31.5 流控效果【排队等待】31.5.1 流控效果【排队等待】31.5.2 案例31.5.3 总结31 限流…

JAVA物业管理系统带小程序源码

源码分享&#xff01;文末卡片查看联系方式获取源码。 基于Web&#xff0c;使用MySQL数据库&#xff0c;使用安全框架&#xff1a;shiro, 使用技术&#xff1a;springspringMVCMybatis&#xff0c;小程序 前端框架&#xff1a;layui 编译器&#xff1a;IntelliJ IDEA 项目构…

Linux消息中间件-RabbitMQ

Linux消息中间件-RabbitMQ 消息中间件 MQ简介 MQ 全称为Message Queue, 消息队列。是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息&#xff08;针对应用程序的数据&#xff09;来通信&#xff0c;而无需专用连接来链接它们。消息传递指的是程序之间通…

Python字符串关键点分析介绍

Python字符串关键点有下面几点&#xff1a; 1.一些引号分隔的字符 你可以把字符串看出是Python的一种数据类型&#xff0c;在Python单引号或者双引号之间的字符数组或者连续的字符集合。在python中最常用的引号为&#xff08;’’&#xff09;和("")。两者的功能是一…

笔试强训(四十一)

目录一、选择题二、编程题2.1 Emacs计算器2.1.1 题目2.1.1 题解一、选择题 &#xff08;1&#xff09;某主机的IP地址为180.80.77.55&#xff0c;子网掩码为255.255.252.0.若该主机向其所在子网发送广播分组&#xff0c;则目的地址可以是&#xff08;D&#xff09; A.180.80.7…

【mmdetection系列】mmdetection之训练框架讲解

这一篇是一个比较宽泛的训练框架讲解与说明。会大致说一些模型训练过程中需要的一些模块&#xff0c;datasets、backbone、neck、head、loss等。会先将框架结构&#xff0c;再讲核心机制。 目录 1.框架结构 1.1 configs 1.1.1 训练配置 1.1.2 datasets 1.1.3 models 1.1.…