springboot-security安全登录

article/2025/9/18 10:44:15

一个简单的security安全登录示例

  1. 配置环境
    1. 添加pom依赖坐标
      <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.6.RELEASE</version></parent><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.0</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version></dependency></dependencies>
    2.  application.yml文件配置
      server:port: 9999
      spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/db_security?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghaiusername: rootpassword: rootmain:allow-bean-definition-overriding: trueredis:port: 6379host: 127.0.0.1
      logging:level:root: INFOorg.springframework.web.servlet.DispatcherServlet: DEBUGorg.springframework.cloud.sleuth: DEBUG
    3.  数据库就一张用户表(简单登录:用户表)
      SET NAMES utf8mb4;
      SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
      -- Table structure for tb_user
      -- ----------------------------
      DROP TABLE IF EXISTS `tb_user`;
      CREATE TABLE `tb_user`  (`id` int(11) NOT NULL,`account` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`username` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`role` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
      ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;-- ----------------------------
      -- Records of tb_user
      -- ----------------------------
      INSERT INTO `tb_user` VALUES (1, '123456', 'admin', '$2a$10$gGKeupjLdvbaoYdAlz1MfuiT/4llYvGFU2QeQ..CQIhCXyqXekn5.', 'test');
      INSERT INTO `tb_user` VALUES (2, '789456', 'zhangsan', '$2a$10$gGKeupjLdvbaoYdAlz1MfuiT/4llYvGFU2QeQ..CQIhCXyqXekn5.', NULL);SET FOREIGN_KEY_CHECKS = 1;
    4. 编写统一返回类
      @Data
      @Accessors(chain = true)
      public class R {//成功状态位private Boolean success;//响应消息private String message;//响应码private Integer code;//响应数据private Object data;private static final String DEFAULT_SUCCESS_MESSAGE = "OK";private static final Integer DEFAULT_SUCCESS_CODE = 20000;private static final String DEFAULT_FALL_MESSAGE = "ERROR";private static final Integer DEFAULT_FALL_CODE = 50000;private R(Boolean success, String message, Integer code, Object data) {this.success = success;this.message = message;this.code = code;this.data = data;}public static R success(){R r = new R(true,DEFAULT_SUCCESS_MESSAGE,DEFAULT_SUCCESS_CODE,null);return r;}public static R success(String message){R r = new R(true,message,DEFAULT_SUCCESS_CODE,null);return r;}public static R success(Object data){R r = new R(true,DEFAULT_SUCCESS_MESSAGE,DEFAULT_SUCCESS_CODE,data);return r;}public static R success(String message,Object data){R r = new R(true,message,DEFAULT_SUCCESS_CODE,data);return r;}public static R fail(){R r = new R(false,DEFAULT_FALL_MESSAGE,DEFAULT_FALL_CODE,null);return r;}public static R fail(String message){R r = new R(false,message,DEFAULT_FALL_CODE,null);return r;}public static R fail(String message,Integer code){R r = new R(false,message,code,null);return r;}
      }
    5.  redis配置
      @Configuration
      public class RedisConfig {/*** retemplate相关配置* @param factory* @return*/@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();// 配置连接工厂template.setConnectionFactory(factory);//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper();// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和publicom.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jacksonSeial.setObjectMapper(om);// 值采用json序列化template.setValueSerializer(jacksonSeial);//使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());// 设置hash key 和value序列化模式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(jacksonSeial);template.afterPropertiesSet();return template;}}
  2.  创建实体类,实现接口UserDetails,实现获取权限方法
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Accessors(chain = true)
    public class UserBean implements UserDetails {private String account;private String username;private String password;private String role;@JSONField(serialize = false)private List<SimpleGrantedAuthority> authorities;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {if (authorities != null) {return authorities;}authorities = new ArrayList<>();if(null!=role){SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(role);authorities.add(simpleGrantedAuthority);}return authorities;}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}
    }

  3.  创建mapper接口,编写sql语句
    @Mapper
    public interface UserBeanMapper {//根据账号查询用户信息@Select("select * from tb_user where account=#{account}")UserBean findUserById(@Param("account")String account);
    }
  4.  创建service层登录接口
    public interface UserBeanService {R login(String account,String password);
    }
  5.  实现service层接口
    @Service
    public class UserServiceImpl implements UserBeanService {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate RedisTemplate<String,Object> redisTemplate;@Overridepublic R login(String account, String password) {
    //创建用户身份验证UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(account, password);Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);if(null==authenticate){return R.fail("账户名或密码错误");}
    //以hash方式存储redis中redisTemplate.boundHashOps(account).put(account, JSON.toJSONString(authenticate.getPrincipal()));
    //设置redis过期时间redisTemplate.boundHashOps(account).expire(100000, TimeUnit.MILLISECONDS);return R.success(JwtUtil.createJWT(account));}
    }
  6.  创建controller层
    @RestController
    public class UserBeanController {@Autowiredprivate UserBeanService userBeanService;//登录@PostMapping("/login")public R login(@RequestParam("account") String account, @RequestParam("password") String password){return userBeanService.login(account,password);}//权限测试@GetMapping("/test")@PreAuthorize("hasAuthority('test')")public R test(){return R.success("这是一条提示消息","test");}
    }

 security相关代码配置

  1. 这里使用jwt令牌,创建jwt工具类
    /*** JWT工具类*/
    public class JwtUtil {//有效期为public static final Long JWT_TTL = 60 * 60 *1000L;// 60 * 60 *1000  一个小时//设置秘钥明文public static final String JWT_KEY = "mingwen";public static String getUUID(){String token = UUID.randomUUID().toString().replaceAll("-", "");return token;}/*** 生成jtw* @param subject token中要存放的数据(json格式)* @return*/public static String createJWT(String subject) {JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 设置过期时间return builder.compact();}/*** 生成jtw* @param subject token中要存放的数据(json格式)* @param ttlMillis token超时时间* @return*/public static String createJWT(String subject, Long ttlMillis) {JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 设置过期时间return builder.compact();}private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;SecretKey secretKey = generalKey();long nowMillis = System.currentTimeMillis();Date now = new Date(nowMillis);if(ttlMillis==null){ttlMillis=JwtUtil.JWT_TTL;}long expMillis = nowMillis + ttlMillis;Date expDate = new Date(expMillis);return Jwts.builder().setId(uuid)              //唯一的ID.setSubject(subject)   // 主题  可以是JSON数据.setIssuer("sanyue")     // 签发者.setIssuedAt(now)      // 签发时间.signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥.setExpiration(expDate);}/*** 创建token* @param id* @param subject* @param ttlMillis* @return*/public static String createJWT(String id, String subject, Long ttlMillis) {JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 设置过期时间return builder.compact();}/*** 生成加密后的秘钥 secretKey* @return*/public static SecretKey generalKey() {byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");return key;}/*** 解析** @param jwt* @return* @throws Exception*/public static Claims parseJWT(String jwt) throws Exception {SecretKey secretKey = generalKey();return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();}}
  2.  创建jwt过滤器
    @Component
    public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@Autowiredprivate RedisTemplate<String,Object> redisTemplate;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {String token = request.getHeader("token");if (!StringUtils.hasText(token)) {filterChain.doFilter(request, response);return;}String account = null;
    //校验tokentry {Claims claims = JwtUtil.parseJWT(token);account = claims.getSubject();} catch (Exception e) {e.printStackTrace();throw new RuntimeException("非法token");}
    //判断redis该用户是否超时存在if(Boolean.FALSE.equals(redisTemplate.boundHashOps(account).hasKey(account))){throw new RuntimeException("用户登录超时请重新登录");}
    //取出该用户相关信息 同时延长redis存储时间String redisUserObj = redisTemplate.boundHashOps(account).get(account).toString();redisTemplate.boundHashOps(account).expire(100000, TimeUnit.MILLISECONDS);UserBean userBean = JSON.parseObject(redisUserObj, UserBean.class);
    //将用户信息,及权限交给securityUsernamePasswordAuthenticationToken authenticationToken=new UsernamePasswordAuthenticationToken(userBean,null,userBean.getAuthorities());SecurityContextHolder.getContext().setAuthentication(authenticationToken);filterChain.doFilter(request, response);}
    }
  3.  继承security适配器,配置security
    @Configuration
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {@Autowiredprivate JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;//密码校验规则@Beanpublic BCryptPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http//关闭csrf.csrf().disable()//不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers("/login").anonymous()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();//把token校验过滤器添加到过滤器链中http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);}@Overridepublic void configure(WebSecurity web) throws Exception {web.ignoring().antMatchers("/login/**","/logout/**");}
    }
  4.  实现接口UserDetailsService 并实现方法,走我们自己的业务逻辑
    @Service
    public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserBeanMapper userBeanMapper;@Overridepublic UserDetails loadUserByUsername(String account) throws UsernameNotFoundException {return userBeanMapper.findUserById(account);}
    }

启动项目

  1. 启动类
    @SpringBootApplication
    public class SecurityApplication {public static void main(String[] args) {ConfigurableApplicationContext run = SpringApplication.run(SecurityApplication.class, args);BCryptPasswordEncoder bean = run.getBean(BCryptPasswordEncoder.class);System.out.println(bean.encode("123456"));}
    }
  2.  测试数据
  3.  admin登录
  4.  admin访问对应权限方法
  5.  zhangsan登录 
  6. zhangsan访问权限方法 

 写的不怎么样,希望对大家有用,希望大家多多指点~~~


http://chatgpt.dhexx.cn/article/fpbCDyu7.shtml

相关文章

如何设计一个安全的登录接口?

Java技术栈 www.javastack.cn 关注阅读更多优质文章 作者&#xff1a;哒哒哒哒打代码链接&#xff1a;juejin.im/post/6859214952704999438 前言 大家学写程序时&#xff0c;第一行代码都是hello world。 但是当你开始学习WEB后台技术时&#xff0c;很多人的第一个功能就是写的…

[OS-Linux] CentOS 7.x 安全登录策略设置

简介 之前用用户名和密码登陆服务器 这样不安全 &#xff0c;用SSH公钥(public key)验证 这个办法能很好的解决 登陆服务器 和安全登陆服务器的特点&#xff1a; 方法 / 步骤 &#x1f510; 一: 证书生成 命令行页面生成 (推荐) 查看执行结果&#xff0c;这时候连续回车即可…

开启QQ登录保护仍被盗号——QQ安全机制全面分析

1、前言 周围总是有些同学QQ被盗号&#xff0c;攻击者盗取账号后会继续去欺骗列表里的好友&#xff0c;形成链式反应。危害比较大。 腾讯QQ安全中心提供了登录保护机制&#xff0c;如图&#xff1a; 这是腾讯为QQ添加第二层保护&#xff0c;在开启登录保护后&#xff0c;盗号者…

使用 PHP 和 MySQL 的安全登录系统

Secure Login System with PHP and MySQL 在本教程中&#xff0c;我将教您如何创建自己的安全 PHP 登录系统。登录表单是您网站的访问者可以用来登录您的网站以访问受限内容&#xff08;例如个人资料页面&#xff09;的表单。我们将利用 MySQL 从数据库中检索帐户数据。 高级…

使用腾讯企业邮箱为什么强烈建议启用安全登录?怎么启用?

腾讯企业邮箱开启安全登录&#xff0c;简单来说就是把企业邮箱账号和微信绑定。启用安全登录和关闭安全登录&#xff0c;主要是登录方式发生了变化。 登录方式&#xff1a; 登录启用前启用后网页端邮箱帐号密码登录/微信扫码登录仅支持微信扫码登录客户端邮箱帐号密码登录仅…

登录安全----双重MD5加密实现安全登录

个人简介&#xff1a; &#x1f4e6;个人主页&#xff1a;肇事司机赵四 &#x1f3c6;学习方向&#xff1a;JAVA后端开发 &#x1f4e3;种一棵树最好的时间是十年前&#xff0c;其次是现在&#xff01; &#x1f9e1;喜欢的话麻烦点点关注喔&#xff0c;你们的支持是我的最大动…

http登录模块加密登录安全登录方法

http请求很容易被截获&#xff0c;在写登录模块时&#xff0c;直接使用明文密码请求&#xff0c;很容易明文密码泄露&#xff1b;若在js页面对密码进行一次加密后在传输&#xff0c;虽不是明文密码&#xff0c;但也完全可以截获加密后的暗文&#xff0c;伪造http请求进行登录。…

安全登录认证

用户登录是任何一个应用系统的基本功能&#xff0c;特别是对于网上银行系统来说&#xff0c;用户登录的安全性尤为重要。如何设计一个网站的安全登录认证程序&#xff0c;是本文主要讨论的问题。 静态密码存在着比较多的安全隐患&#xff0c;攻击者有很多手段获得静态密码&…

Web登录如何确保安全

1、一个普通简单的HTML例子&#xff0c;用户登录信息是不安全的 <form action "http://localhost:8080/Application/login" method "POST"> 用户名&#xff1a;<input id"username" name"username" type"te…

实现安全登录的两种方法

登录安全——拦截器和过滤器或权限框架的使用 本次我们将采用两种方法实现登录的安全性&#xff0c;首先介绍拦截器和过滤器。 一、 过滤器和拦截器&#xff1a; 过滤器产生的时间/开始工作的时间&#xff1a; 进入Tomcat之后&#xff0c;但是在进servlet之前。Interceptor进入…

推荐几款优秀的搜素引擎

秘迹搜索 网址&#xff1a;https://mijisou.com/ 秘迹搜索是一款守护用户搜索信息的聚合搜索引擎&#xff0c;Ta不会根据搜索关键词追踪用户&#xff0c;也不会通过历史搜索内容做广告推荐。秘迹搜索通过聚合中文搜索服务比如Bing、百度、360、搜狗等搜索结果提供私密搜索服务…

12.推荐几款好用的搜索引擎

1.goobe https://goobe.io/ 专为程序员设计的搜索引擎&#xff08;搜索非技术相关的东西也很6&#xff09;&#xff0c;界面是这样事儿的 而且可以通过快照访问stackoverflow和github&#xff0c;非常好用 无广告&#xff0c;不跟踪 2.萌搜 https://mengso.com/ 号称小众的…

《搜索和推荐中的深度匹配》——1.1搜索和推荐

重磅推荐专栏&#xff1a; 《Transformers自然语言处理系列教程》 手把手带你深入实践Transformers&#xff0c;轻松构建属于自己的NLP智能应用&#xff01; 随着Internet的快速发展&#xff0c;当今信息科学的基本问题之一变得更加重要&#xff0c;即如何从通常庞大的信息库中…

基于Elasticsearch实现搜索推荐

在基于Elasticsearch实现搜索建议一文中我们曾经介绍过如何基于Elasticsearch来实现搜索建议&#xff0c;而本文是在此基于上进一步优化搜索体验&#xff0c;在当搜索无结果或结果过少时提供推荐搜索词给用户。 背景介绍 在根据用户输入和筛选条件进行搜索后&#xff0c;有时…

五个小众好用的搜索引擎

一、wikiHow https://zh.wikihow.com/ 我把wikiHow当做一个帮我做任何事的搜索引擎 wikiHow上每一篇详尽明了的指南文章 都能改善成百上千人的生活 与维基百科类似&#xff0c;wikiHow 也采用了维基技术 所有人都可以创建或编辑文章中的内容 来自全球的协作者们已编写了…

阿里搜索推荐系统

一、系统框架 导购升级的优化思路从三个方向着手&#xff1a;1.策略升级。利用深度学习及异构网络的思想&#xff0c;对用户个性化进行更深的理解和建模&#xff1b;同时对因马太效应引起的独立query数下降等问题进行优化。 2.导购外投。在包括会场激活页、猜你喜欢等渠道进行搜…

推荐和搜索系统的多样性研究综述

前言 检索结果的多样化是检索系统的一个重要研究课题&#xff0c;其可以满足用户的各种兴趣和供应商的平等公平曝光。 然而&#xff0c;检索系统中&#xff08;搜索与推荐领域&#xff09;的多样性研究缺乏一个系统的汇总&#xff0c;并且研究点相对零散。本次介绍的paper中&am…

从零开始搭建搜索推荐系统(五十二)ElasticSearch搜索利器

聊的不止技术。跟着小帅写代码&#xff0c;还原和技术大牛一对一真实对话&#xff0c;剖析真实项目筑成的一砖一瓦&#xff0c;了解最新最及时的资讯信息&#xff0c;还可以学到日常撩妹小技巧哦&#xff0c;让我们开始探索主人公小帅的职场生涯吧&#xff01; &#xff08;PS…

《智能搜索和推荐系统》总结

这本书主要分为4部分介绍&#xff0c;分别是搜索和推荐的基础&#xff0c;搜索系统基本原理&#xff0c;推荐系统的基本原理&#xff0c;工程应用。 第一部分&#xff1a;搜索和推荐的基础 主要讲了一下概率统计与应用数学的基础知识&#xff0c;比如概率论基础&#xff08;概率…

推荐系统与搜索引擎的差异

转自&#xff1a;https://blog.csdn.net/cserchen/article/details/50422553 详细分析推荐系统和搜索引擎的差异陈运文 从信息获取的角度来看&#xff0c;搜索和推荐是用户获取信息的两种主要手段。无论在互联网上&#xff0c;还是在线下的场景里&#xff0c;搜索和推荐这两种方…