96SEO 2026-02-19 18:00 0
来做安全框架#xff0c;小项目用相对简单的Shiro。

认证、授权是
认证#xff1a;通过用户名密码验证当前访问系统的是不是本…Spring
认证通过用户名密码验证当前访问系统的是不是本系统的用户并且要确认具体是哪个用户。
授权经过认证后判断当前用户是否有权限进行某个操作。
B站视频链接SpringSecurity框架教程-Spring
Authentication接口它的实现类表示当前访问系统的用户封装了用户相关信息。
AuthenticationManager接口定义了认证
authenticate()UserDetailsService接口加载用户特定数据的核心接口。
里面定义了一个根据用户名查询用户信息的方法loadUserByUsername()。
UserDetails接口提供核心用户信息。
通过
UserDetailsService接口在这个实现类中去查询数据库。
xmlnshttp://maven.apache.org/POM/4.0.0
xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdorg.ymqx/groupIdartifactIdSpringSecurityDemo/artifactIdversion1.0-SNAPSHOT/versionnameSpringSecurityDemo/namepropertiesproject.build.sourceEncodingUTF-8/project.build.sourceEncodingmaven.compiler.source1.8/maven.compiler.sourcemaven.compiler.target1.8/maven.compiler.target/propertiesparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.5.0/version/parentdependencies!--web--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!--lombok--dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependency!--security--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-security/artifactId/dependency!--mybatis-plus--dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.4.3/version/dependency!--mysql--dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependency/dependencies
/project引入依赖spring-boot-starter-security
1、根据用户名查询用户信息LambdaQueryWrapperUser
LambdaQueryWrapper();wrapper.eq(User::getUserName,
userMapper.selectOne(wrapper);//
1.1、如果查询不到数据就通过抛出异常来给出提示if(Objects.isNull(user)){throw
3、封装成UserDetails对象返回UserDetails
实现UserDetailsService接口重写loadUserByUsername()方法内部实现查询数据库逻辑将获取的用户信息封装成UserDetails对象返回。
user.getPassword();}Overridepublic
user.getUserName();}Overridepublic
jdbc:mysql://localhost:3306/sg_security?characterEncodingutf-8serverTimezoneUTCusername:
默认使用的PasswordEncoder要求数据库中的密码格式为{id}password
。
它会根据id去判断密码的加密方式。
但是我们一般不会采用这种方式。
所以就需要替换PasswordEncoder。
我们一般使用SpringSecurity为我们提供的BCryptPasswordEncoder。
我们只需要使用把BCryptPasswordEncoder对象注入Spring容器中SpringSecurity就会使用该PasswordEncoder来进行密码校验。
我们可以定义一个
要求这个配置类要继承WebSecurityConfigurerAdapter。
passwordEncoder.encode(123456);System.out.println(encode);boolean
passwordEncoder.matches(123456,
encode);System.out.println(matches);}
$2a$10$V.th3Vaeh9lzPJmtyM3A7eqL9YRZ1Cv4By4KmJN2F6t5bng6P4UFG
true字符串123456生成的密文插入到用户表sys_user
sys_user(user_name,nick_name,password,status,email,phonenumber,sex,avatar,user_type,create_by,create_time,update_by,update_time,del_flag)
values(sg,三更,$2a$10$V.th3Vaeh9lzPJmtyM3A7eqL9YRZ1Cv4By4KmJN2F6t5bng6P4UFG,0,null,123456789,男,,0,0,2022-06-01,0,2022-06-01,0)1.5
{SpringApplication.run(SecurityApplication.class,args);}
入门案例每次访问资源都要重新认证而且需要使用SpringSecurity默认的login页面所以我们需要自定义登录接口。
通过入门的认证流程图可知通过AuthenticationManager的authenticate()方法来进行用户认证同时需要将登录接口进行放行让用户访问这个接口的时候不用登录也能访问。
认证成功的话要生成一个JWT放入响应中返回。
并且为了让用户下回请求时能通过JWT识别出具体的是哪个用户我们需要把用户信息存入redis可以把用户
UserDetailsService在这个实现类中去查询数据库。
已经实现
中获取用户信息存入SecurityContextHolder。
!--redis依赖--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependency!--
--dependencygroupIdorg.apache.commons/groupIdartifactIdcommons-pool2/artifactId/dependency!--fastjson依赖--dependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion1.2.33/version/dependency!--jwt依赖--dependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt/artifactIdversion0.9.0/version/dependency2.2
clazz;static{ParserConfig.getGlobalInstance().setAutoTypeSupport(true);}public
SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);}Overridepublic
TypeFactory.defaultInstance().constructType(clazz);}
redisTemplate(RedisConnectionFactory
connectionFactory){RedisTemplateObject,
RedisTemplate();template.setConnectionFactory(connectionFactory);FastJsonRedisSerializer
FastJsonRedisSerializer(Object.class);//
使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new
StringRedisSerializer());template.setValueSerializer(serializer);//
Hash的key也采用StringRedisSerializer的序列化方式template.setHashKeySerializer(new
StringRedisSerializer());template.setHashValueSerializer(serializer);template.afterPropertiesSet();return
value){redisTemplate.opsForValue().set(key,
timeUnit){redisTemplate.opsForValue().set(key,
redisTemplate.opsForValue();return
redisTemplate.delete(key);}/***
redisTemplate.delete(collection);}/***
redisTemplate.opsForList().rightPushAll(key,
redisTemplate.opsForList().range(key,
dataSet){BoundSetOperationsString,
redisTemplate.boundSetOps(key);IteratorT
(it.hasNext()){setOperation.add(it.next());}return
redisTemplate.opsForSet().members(key);}/***
{redisTemplate.opsForHash().putAll(key,
redisTemplate.opsForHash().entries(key);}/***
value){redisTemplate.opsForHash().put(key,
redisTemplate.opsForHash();return
redisTemplate.opsForHash();hashOperations.delete(key,
redisTemplate.opsForHash().multiGet(key,
UUID.randomUUID().toString().replaceAll(-,
Base64.getDecoder().decode(JwtUtil.JWT_KEY);SecretKey
SignatureAlgorithm.HS256;SecretKey
System.currentTimeMillis();Date
Date(nowMillis);if(ttlMillisnull){ttlMillisJwtUtil.JWT_TTL;}long
Date(expMillis);System.out.println(uuid);System.out.println(subject);System.out.println(secretKey);System.out.println(expDate);return
签发时间.signWith(signatureAlgorithm,
第二个参数为秘钥.setExpiration(expDate);}/***
Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();}public
JwtUtil.createJWT({usershwen});System.out.println(jwt);*///
60*1000L);System.out.println(jwt);//过期JWT解析会抛出异常String
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI1ODljMGE0MDQ0Y2Y0YmJiYmFhYjFiOWFmOTMzYzc3ZiIsInN1YiI6Int1c2VyPXNod2VufSIsImlzcyI6ImFkbWluIiwiaWF0IjoxNjk5MjczMzE0LCJleHAiOjE2OTkyNzMzNzR9.xMOjtNp2AESTjuSq9G75DaZh9M1dDuLDr4s7yw-xw_Q;Claims
parseJWT(token);System.out.println(claims);}
renderString(HttpServletResponse
{try{response.setStatus(200);response.setContentType(application/json);response.setCharacterEncoding(utf-8);response.getWriter().print(string);}catch
的authenticate()方法来进行用户认证。
SpringSecurity对登录接口进行放行。
注入AuthenticationManager对登录接口进行放行。
super.authenticationManagerBean();}//
antMatchers(/user/login).anonymous()Overrideprotected
{http//关闭csrf.csrf().disable()//不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()//
允许匿名访问.antMatchers(/user/login).anonymous()//
除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();}
org.ymqx.domain.ResponseResult;
authenticationManager;Autowiredprivate
1、自定义authenticationTokenUsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());Authentication
authenticationManager.authenticate(authenticationToken);if(Objects.isNull(authenticate)){throw
authenticate.getPrincipal();String
loginUser.getUser().getId().toString();String
userId;System.out.println(key);redisCache.setCacheObject(key,
4、把token响应给前端HashMapString,String
SecurityContextHolder.getContext().getAuthentication();//
authentication.getPrincipal();Long
loginUser.getUser().getId();redisCache.deleteObject(login:
提示信息如果有错误时前端可以获取该字段进行提示*/private
loginServcie;PostMapping(/user/login)public
中获取用户信息存入SecurityContextHolder。
filter.JwtAuthenticationTokenFilter
doFilterInternal(HttpServletRequest
request.getHeader(token);System.out.println(token
{//放行filterChain.doFilter(request,
claims.getSubject();System.out.println(userid
redisCache.getCacheObject(redisKey);System.out.println(id
loginUser.getUser().getId());if(Objects.isNull(loginUser)){throw
4、存入SecurityContextHolder//TODO
获取权限信息封装到Authentication中UsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken(loginUser,null,null);SecurityContextHolder.getContext().setAuthentication(authenticationToken);//
5、放行filterChain.doFilter(request,
{AutowiredJwtAuthenticationTokenFilter
jwtAuthenticationTokenFilter;Overrideprotected
{http//关闭csrf.csrf().disable()//不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()//
允许匿名访问.antMatchers(/user/login).anonymous()//
除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();//把token校验过滤器添加到过滤器链中http.addFilterBefore(jwtAuthenticationTokenFilter,
UsernamePasswordAuthenticationFilter.class);}...
}http.addFilterBefore(jwtAuthenticationTokenFilter,
UsernamePasswordAuthenticationFilter.class);
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback