目录
简介
Security
是
Spring
家族中的一个安全管理框架。相比与另外一个安全框架
Shiro
,它提供了更丰富的功能,社区资源也比Shiro丰富。
具体介绍和入门看springSecurity入门
原理初探
在实现之前幺要了解一下登录校验的流程以及
SpringSecurity
的原理以及认证流程
1、登录校验流程
2、 SpringSecurity完整流程
SpringSecurity
的原理其实就是一个过滤器链,内部包含了提供各种功能的过滤器。这里我们可以看看入门案例中的过滤器。
图中只展示了核心过滤器,其它的非核心过滤器并没有在图中展示。
UsernamePasswordAuthenticationFilter:负责处理我们在登陆页面填写了用户名密码后的登陆请求。入门案例的认证工作主要有它负责。
ExceptionTranslationFilter:处理过滤器链中抛出的任何
AccessDeniedException
和
AuthenticationException
。
FilterSecurityInterceptor:负责权限校验的过滤器。
我们可以通过
Debug
查看当前系统中
SpringSecurity
过滤器链中有哪些过滤器及它们的顺序。
3、认证流程
概念速查:
Authentication
接口: 它的实现类,表示当前访问系统的用户,封装了用户相关信息。AuthenticationManager
接口:定义了认证Authentication的方法UserDetailsService
接口:加载用户特定数据的核心接口。里面定义了一个根据用户名查询用户信息的方法。UserDetails
接口:提供核心用户信息。通过UserDetailsService
根据用户名获取处理的用户信息要封装成UserDetails
对象返回。然后将这些信息封装到Authentication
对象中。
实现思路
登录
①自定义登录接口
调用
ProviderManager
的方法进行认证 如果认证通过生成
jwt
把用户信息存入
redis
中
②自定义
UserDetailsService
在这个实现类中去查询数据库
校验:
①定义Jwt认证过滤器
获取
token
解析
token
获取其中的
userid
从
redis
中获取用户信息
存入
SecurityContextHolder
这里我们主要是实现登录接口的功能
核心思想就是就是将
认证流程
中的
UserDetailsService
重写其
loadUserByUsername
的方法,使其从数据库中查询数据,然后用自己的类(我这里是
UserLogin
)实现
UserDetails
,在
loadUserByUsername
中返回
UserLogin
登录接口实现
准备工作
添加依赖,添加工具类,创建数据库,编写配置文件
1、添加依赖
<!--redis依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!--fastjson依赖--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.33</version></dependency><!--jwt依赖--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.0</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency>
2、添加Redis相关配置
importcom.alibaba.fastjson.JSON;importcom.alibaba.fastjson.serializer.SerializerFeature;importcom.fasterxml.jackson.databind.JavaType;importcom.fasterxml.jackson.databind.ObjectMapper;importcom.fasterxml.jackson.databind.type.TypeFactory;importorg.springframework.data.redis.serializer.RedisSerializer;importorg.springframework.data.redis.serializer.SerializationException;importcom.alibaba.fastjson.parser.ParserConfig;importorg.springframework.util.Assert;importjava.nio.charset.Charset;/**
* Redis使用FastJson序列化
*
* @author sg
*/publicclassFastJsonRedisSerializer<T>implementsRedisSerializer<T>{publicstaticfinalCharsetDEFAULT_CHARSET=Charset.forName("UTF-8");privateClass<T> clazz;static{ParserConfig.getGlobalInstance().setAutoTypeSupport(true);}publicFastJsonRedisSerializer(Class<T> clazz){super();this.clazz = clazz;}@Overridepublicbyte[]serialize(T t)throwsSerializationException{if(t ==null){returnnewbyte[0];}returnJSON.toJSONString(t,SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);}@OverridepublicTdeserialize(byte[] bytes)throwsSerializationException{if(bytes ==null|| bytes.length <=0){returnnull;}String str =newString(bytes,DEFAULT_CHARSET);returnJSON.parseObject(str, clazz);}protectedJavaTypegetJavaType(Class<?> clazz){returnTypeFactory.defaultInstance().constructType(clazz);}}
importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.data.redis.connection.RedisConnectionFactory;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.data.redis.serializer.StringRedisSerializer;@ConfigurationpublicclassRedisConfig{@Bean@SuppressWarnings(value ={"unchecked","rawtypes"})publicRedisTemplate<Object,Object>redisTemplate(RedisConnectionFactory connectionFactory){RedisTemplate<Object,Object> template =newRedisTemplate<>();
template.setConnectionFactory(connectionFactory);FastJsonRedisSerializer serializer =newFastJsonRedisSerializer(Object.class);// 使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(newStringRedisSerializer());
template.setValueSerializer(serializer);// Hash的key也采用StringRedisSerializer的序列化方式
template.setHashKeySerializer(newStringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();return template;}}
封装返回的数据
importcom.fasterxml.jackson.annotation.JsonInclude;@JsonInclude(JsonInclude.Include.NON_NULL)publicclassResponseResult<T>{/**
* 状态码
*/privateInteger code;/**
* 提示信息,如果有错误时,前端可以获取该字段进行提示
*/privateString msg;/**
* 查询到的结果数据,
*/privateT data;publicResponseResult(Integer code,String msg){this.code = code;this.msg = msg;}publicResponseResult(Integer code,T data){this.code = code;this.data = data;}publicIntegergetCode(){return code;}publicvoidsetCode(Integer code){this.code = code;}publicStringgetMsg(){return msg;}publicvoidsetMsg(String msg){this.msg = msg;}publicTgetData(){return data;}publicvoidsetData(T data){this.data = data;}publicResponseResult(Integer code,String msg,T data){this.code = code;this.msg = msg;this.data = data;}}
JWT工具类
importio.jsonwebtoken.Claims;importio.jsonwebtoken.JwtBuilder;importio.jsonwebtoken.Jwts;importio.jsonwebtoken.SignatureAlgorithm;importjavax.crypto.SecretKey;importjavax.crypto.spec.SecretKeySpec;importjava.util.Base64;importjava.util.Date;importjava.util.UUID;/**
* JWT工具类
*/publicclassJwtUtil{//有效期为publicstaticfinalLongJWT_TTL=60*60*1000L;// 60 * 60 *1000 一个小时//设置秘钥明文publicstaticfinalStringJWT_KEY="sangeng";publicstaticStringgetUUID(){String token =UUID.randomUUID().toString().replaceAll("-","");return token;}/**
* 生成jtw
* @param subject token中要存放的数据(json格式)
* @return
*/publicstaticStringcreateJWT(String subject){JwtBuilder builder =getJwtBuilder(subject,null,getUUID());// 设置过期时间return builder.compact();}/**
* 生成jtw
* @param subject token中要存放的数据(json格式)
* @param ttlMillis token超时时间
* @return
*/publicstaticStringcreateJWT(String subject,Long ttlMillis){JwtBuilder builder =getJwtBuilder(subject, ttlMillis,getUUID());// 设置过期时间return builder.compact();}privatestaticJwtBuildergetJwtBuilder(String subject,Long ttlMillis,String uuid){SignatureAlgorithm signatureAlgorithm =SignatureAlgorithm.HS256;SecretKey secretKey =generalKey();long nowMillis =System.currentTimeMillis();Date now =newDate(nowMillis);if(ttlMillis==null){
ttlMillis=JwtUtil.JWT_TTL;}long expMillis = nowMillis + ttlMillis;Date expDate =newDate(expMillis);returnJwts.builder().setId(uuid)//唯一的ID.setSubject(subject)// 主题 可以是JSON数据.setIssuer("sg")// 签发者.setIssuedAt(now)// 签发时间.signWith(signatureAlgorithm, secretKey)//使用HS256对称加密算法签名, 第二个参数为秘钥.setExpiration(expDate);}/**
* 创建token
* @param id
* @param subject
* @param ttlMillis
* @return
*/publicstaticStringcreateJWT(String id,String subject,Long ttlMillis){JwtBuilder builder =getJwtBuilder(subject, ttlMillis, id);// 设置过期时间return builder.compact();}publicstaticvoidmain(String[] args)throwsException{String token ="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJjYWM2ZDVhZi1mNjVlLTQ0MDAtYjcxMi0zYWEwOGIyOTIwYjQiLCJzdWIiOiJzZyIsImlzcyI6InNnIiwiaWF0IjoxNjM4MTA2NzEyLCJleHAiOjE2MzgxMTAzMTJ9.JVsSbkP94wuczb4QryQbAke3ysBDIL5ou8fWsbt_ebg";Claims claims =parseJWT(token);System.out.println(claims);}/**
* 生成加密后的秘钥 secretKey
* @return
*/publicstaticSecretKeygeneralKey(){byte[] encodedKey =Base64.getDecoder().decode(JwtUtil.JWT_KEY);SecretKey key =newSecretKeySpec(encodedKey,0, encodedKey.length,"AES");return key;}/**
* 解析
*
* @param jwt
* @return
* @throws Exception
*/publicstaticClaimsparseJWT(String jwt)throwsException{SecretKey secretKey =generalKey();returnJwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();}}
Redis工具类
importjava.util.*;importjava.util.concurrent.TimeUnit;@SuppressWarnings(value ={"unchecked","rawtypes"})@ComponentpublicclassRedisCache{@AutowiredpublicRedisTemplate redisTemplate;/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
*/public<T>voidsetCacheObject(finalString key,finalT value){
redisTemplate.opsForValue().set(key, value);}/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/public<T>voidsetCacheObject(finalString key,finalT value,finalInteger timeout,finalTimeUnit timeUnit){
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);}/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @return true=设置成功;false=设置失败
*/publicbooleanexpire(finalString key,finallong timeout){returnexpire(key, timeout,TimeUnit.SECONDS);}/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @param unit 时间单位
* @return true=设置成功;false=设置失败
*/publicbooleanexpire(finalString key,finallong timeout,finalTimeUnit unit){return redisTemplate.expire(key, timeout, unit);}/**
* 获得缓存的基本对象。
*
* @param key 缓存键值
* @return 缓存键值对应的数据
*/public<T>TgetCacheObject(finalString key){ValueOperations<String,T> operation = redisTemplate.opsForValue();return operation.get(key);}/**
* 删除单个对象
*
* @param key
*/publicbooleandeleteObject(finalString key){return redisTemplate.delete(key);}/**
* 删除集合对象
*
* @param collection 多个对象
* @return
*/publiclongdeleteObject(finalCollection collection){return redisTemplate.delete(collection);}/**
* 缓存List数据
*
* @param key 缓存的键值
* @param dataList 待缓存的List数据
* @return 缓存的对象
*/public<T>longsetCacheList(finalString key,finalList<T> dataList){Long count = redisTemplate.opsForList().rightPushAll(key, dataList);return count ==null?0: count;}/**
* 获得缓存的list对象
*
* @param key 缓存的键值
* @return 缓存键值对应的数据
*/public<T>List<T>getCacheList(finalString key){return redisTemplate.opsForList().range(key,0,-1);}/**
* 缓存Set
*
* @param key 缓存键值
* @param dataSet 缓存的数据
* @return 缓存数据的对象
*/public<T>BoundSetOperations<String,T>setCacheSet(finalString key,finalSet<T> dataSet){BoundSetOperations<String,T> setOperation = redisTemplate.boundSetOps(key);Iterator<T> it = dataSet.iterator();while(it.hasNext()){
setOperation.add(it.next());}return setOperation;}/**
* 获得缓存的set
*
* @param key
* @return
*/public<T>Set<T>getCacheSet(finalString key){return redisTemplate.opsForSet().members(key);}/**
* 缓存Map
*
* @param key
* @param dataMap
*/public<T>voidsetCacheMap(finalString key,finalMap<String,T> dataMap){if(dataMap !=null){
redisTemplate.opsForHash().putAll(key, dataMap);}}/**
* 获得缓存的Map
*
* @param key
* @return
*/public<T>Map<String,T>getCacheMap(finalString key){return redisTemplate.opsForHash().entries(key);}/**
* 往Hash中存入数据
*
* @param key Redis键
* @param hKey Hash键
* @param value 值
*/public<T>voidsetCacheMapValue(finalString key,finalString hKey,finalT value){
redisTemplate.opsForHash().put(key, hKey, value);}/**
* 获取Hash中的数据
*
* @param key Redis键
* @param hKey Hash键
* @return Hash中的对象
*/public<T>TgetCacheMapValue(finalString key,finalString hKey){HashOperations<String,String,T> opsForHash = redisTemplate.opsForHash();return opsForHash.get(key, hKey);}/**
* 删除Hash中的数据
*
* @param key
* @param hkey
*/publicvoiddelCacheMapValue(finalString key,finalString hkey){HashOperations hashOperations = redisTemplate.opsForHash();
hashOperations.delete(key, hkey);}/**
* 获取多个Hash中的数据
*
* @param key Redis键
* @param hKeys Hash键集合
* @return Hash对象集合
*/public<T>List<T>getMultiCacheMapValue(finalString key,finalCollection<Object> hKeys){return redisTemplate.opsForHash().multiGet(key, hKeys);}/**
* 获得缓存的基本对象列表
*
* @param pattern 字符串前缀
* @return 对象列表
*/publicCollection<String>keys(finalString pattern){return redisTemplate.keys(pattern);}}
将字符串渲染到客户端工具类
importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;publicclassWebUtils{/**
* 将字符串渲染到客户端
*
* @param response 渲染对象
* @param string 待渲染的字符串
* @return null
*/publicstaticStringrenderString(HttpServletResponse response,String string){try{
response.setStatus(200);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);}catch(IOException e){
e.printStackTrace();}returnnull;}}
SQL语句创建用户表
CREATETABLE `sys_user` (
`id` BIGINT(20)NOTNULLAUTO_INCREMENTCOMMENT'主键',
`user_name` VARCHAR(64)NOTNULLDEFAULT'NULL'COMMENT'用户名',
`nick_name` VARCHAR(64)NOTNULLDEFAULT'NULL'COMMENT'昵称',
`password` VARCHAR(64)NOTNULLDEFAULT'NULL'COMMENT'密码',
`status` CHAR(1)DEFAULT'0'COMMENT '账号状态(0正常 1停用)',
`email` VARCHAR(64)DEFAULTNULLCOMMENT'邮箱',
`phonenumber` VARCHAR(32)DEFAULTNULLCOMMENT'手机号',
`sex` CHAR(1)DEFAULTNULLCOMMENT '用户性别(0男,1女,2未知)',
`avatar` VARCHAR(128)DEFAULTNULLCOMMENT'头像',
`user_type` CHAR(1)NOTNULLDEFAULT'1'COMMENT '用户类型(0管理员,1普通用户)',
`create_by` BIGINT(20)DEFAULTNULLCOMMENT '创建人的用户id',
`create_time` DATETIMEDEFAULTNULLCOMMENT'创建时间',
`update_by` BIGINT(20)DEFAULTNULLCOMMENT'更新人',
`update_time` DATETIMEDEFAULTNULLCOMMENT'更新时间',
`del_flag` INT(11)DEFAULT'0'COMMENT '删除标志(0代表未删除,1代表已删除)',PRIMARYKEY(`id`))ENGINE=INNODBAUTO_INCREMENT=2DEFAULTCHARSET=utf8mb4 COMMENT='用户表'
配置文件
spring:
datasource:
driver-class-name:com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/你的数据库名称?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8
username:****
password:****
redis:
# Redis服务器地址
host:127.0.0.1
# Redis服务器连接端口
port:6379
# Redis服务器连接密码
password:
# Redis数据库索引
database:3
# 连接超时时间(毫秒)
timeout:30000
lettuce:
pool:
max-active:50
max-wait:-1
max-idle:50
min-idle:1
编码实现
目录结构
关于
Email
的类不用管
配置类
RedisConfig类
packagecom.zzuli.common.config;importcom.zzuli.common.utils.FastJsonRedisSerializer;importorg.springframework.data.redis.connection.RedisConnectionFactory;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.data.redis.serializer.StringRedisSerializer;publicclassRedisConfig{publicRedisTemplate<Object,Object>redisTemplate(RedisConnectionFactory connectionFactory){RedisTemplate<Object,Object> template =newRedisTemplate<>();
template.setConnectionFactory(connectionFactory);FastJsonRedisSerializer serializer =newFastJsonRedisSerializer(Object.class);// 使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(newStringRedisSerializer());
template.setValueSerializer(serializer);// Hash的key也采用StringRedisSerializer的序列化方式
template.setHashKeySerializer(newStringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();return template;}}
SecurityConfig
类
packagecom.zzuli.common.config;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.security.authentication.AuthenticationManager;importorg.springframework.security.config.annotation.web.builders.HttpSecurity;importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;importorg.springframework.security.config.http.SessionCreationPolicy;importorg.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;importorg.springframework.security.crypto.password.PasswordEncoder;/**
* @author niuben
*/@ConfigurationpublicclassSecurityConfigextendsWebSecurityConfigurerAdapter{//创建BCryptPasswordEncoder注入容器@BeanpublicPasswordEncoderpasswordEncoder(){returnnewBCryptPasswordEncoder();}@Overrideprotectedvoidconfigure(HttpSecurity http)throwsException{
http
//关闭csrf.csrf().disable()//不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()// 对于登录接口 允许匿名访问.antMatchers("/user/login").anonymous()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();}@Bean@OverridepublicAuthenticationManagerauthenticationManagerBean()throwsException{returnsuper.authenticationManagerBean();}}
实体类
User类
packagecom.zzuli.pojo;importcom.baomidou.mybatisplus.annotation.TableId;importcom.baomidou.mybatisplus.annotation.TableName;importlombok.AllArgsConstructor;importlombok.Data;importlombok.NoArgsConstructor;importjava.io.Serializable;importjava.util.Date;/**
* 用户表(User)实体类
*
* @author 三更
*/@Data@AllArgsConstructor@NoArgsConstructor@TableName("sys_user")//数据库的用户名名称publicclassUserimplementsSerializable{privatestaticfinallong serialVersionUID =-40356785423868312L;/**
* 主键
*/@TableIdprivateLong id;/**
* 用户名
*/privateString userName;/**
* 昵称
*/privateString nickName;/**
* 密码
*/privateString password;/**
* 账号状态(0正常 1停用)
*/privateString status;/**
* 邮箱
*/privateString email;/**
* 手机号
*/privateString phonenumber;/**
* 用户性别(0男,1女,2未知)
*/privateString sex;/**
* 头像
*/privateString avatar;/**
* 用户类型(0管理员,1普通用户)
*/privateString userType;/**
* 创建人的用户id
*/privateLong createBy;/**
* 创建时间
*/privateDate createTime;/**
* 更新人
*/privateLong updateBy;/**
* 更新时间
*/privateDate updateTime;/**
* 删除标志(0代表未删除,1代表已删除)
*/privateInteger delFlag;}
UserLogin
类
继承
UserDetails
packagecom.zzuli.pojo;importlombok.AllArgsConstructor;importlombok.Data;importlombok.NoArgsConstructor;importorg.springframework.security.core.GrantedAuthority;importorg.springframework.security.core.userdetails.UserDetails;importjava.util.Collection;/**
* @author niuben
*/@AllArgsConstructor@NoArgsConstructor@DatapublicclassUserLoginimplementsUserDetails{privateUser user;@OverridepublicCollection<?extendsGrantedAuthority>getAuthorities(){returnnull;}@OverridepublicStringgetPassword(){return user.getPassword();}@OverridepublicStringgetUsername(){return user.getUserName();}@OverridepublicbooleanisAccountNonExpired(){returntrue;}@OverridepublicbooleanisAccountNonLocked(){returntrue;}@OverridepublicbooleanisCredentialsNonExpired(){returntrue;}@OverridepublicbooleanisEnabled(){returntrue;}}
接口实现类
LoginController
接口
packagecom.zzuli.controller;importcom.zzuli.common.api.CommonResult;importcom.zzuli.pojo.User;importcom.zzuli.service.LoginService;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RequestBody;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjavax.annotation.Resource;/**
* @author niuben
*/@RestControllerpublicclassLoginController{@ResourceprivateLoginService loginService;@PostMapping("/user/login")publicCommonResult<Object>login(@RequestBodyUser user){CommonResult<Object> result =null;try{
result = loginService.login(user);}catch(Exception e){returnCommonResult.success("账户或者密码错误!");}return result;}}
UserDetailsServiceImpl
实现类
packagecom.zzuli.service.impl;importcom.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;importcom.zzuli.mapper.UserMapper;importcom.zzuli.pojo.User;importcom.zzuli.pojo.UserLogin;importorg.springframework.security.core.userdetails.UserDetails;importorg.springframework.security.core.userdetails.UserDetailsService;importorg.springframework.security.core.userdetails.UsernameNotFoundException;importorg.springframework.stereotype.Service;importjavax.annotation.Resource;importjava.util.Objects;/**
* @author niuben
*/@ServicepublicclassUserDetailsServiceImplimplementsUserDetailsService{@ResourceprivateUserMapper userMapper;@OverridepublicUserDetailsloadUserByUsername(String username)throwsUsernameNotFoundException{//查询用户信息LambdaQueryWrapper<User> queryWrapper =newLambdaQueryWrapper<User>();
queryWrapper.eq(User::getUserName,username);User user = userMapper.selectOne(queryWrapper);//如果没有查询到用户,就抛出异常if(Objects.isNull(user)){thrownewRuntimeException("用户名或者密码错误!");}//将数据封装成UserDetailsreturnnewUserLogin(user);}}
LoginService
接口
packagecom.zzuli.service;importcom.zzuli.common.api.CommonResult;importcom.zzuli.pojo.User;/**
* @author niuben
*/publicinterfaceLoginService{CommonResult<Object>login(User user);}
LoginService
实现接口
packagecom.zzuli.service.impl;importcom.zzuli.common.api.CommonResult;importcom.zzuli.common.utils.JwtUtil;importcom.zzuli.common.utils.RedisCache;importcom.zzuli.pojo.User;importcom.zzuli.pojo.UserLogin;importcom.zzuli.service.LoginService;importorg.springframework.security.authentication.AuthenticationManager;importorg.springframework.security.authentication.UsernamePasswordAuthenticationToken;importorg.springframework.security.core.Authentication;importorg.springframework.stereotype.Service;importjavax.annotation.Resource;importjava.util.HashMap;importjava.util.Map;importjava.util.Objects;/**
* @author niuben
*/@ServicepublicclassLoginServiceImplimplementsLoginService{@ResourceprivateAuthenticationManager authenticationManager;@ResourceprivateRedisCache redisCache;@OverridepublicCommonResult<Object>login(User user){//进行用户认证UsernamePasswordAuthenticationToken authenticationToken =newUsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());Authentication authenticate = authenticationManager.authenticate(authenticationToken);//认证未通过,给出提示if(Objects.isNull(authenticate)){thrownewRuntimeException("登陆失败!");}//通过了,生成jwtUserLogin loginUser =(UserLogin) authenticate.getPrincipal();String id = loginUser.getUser().getId().toString();String jwt =JwtUtil.createJWT(id);Map<String,String> map =newHashMap<>();
map.put("token",jwt);//将用户信息存入redis
redisCache.setCacheObject("login"+id,loginUser);returnCommonResult.success(map,"登陆成功!");}}
UserMapper
类
packagecom.zzuli.mapper;importcom.baomidou.mybatisplus.core.mapper.BaseMapper;importcom.zzuli.pojo.User;publicinterfaceUserMapperextendsBaseMapper<User>{}
启动类
packagecom.zzuli;importorg.apache.ibatis.annotations.Mapper;importorg.mybatis.spring.annotation.MapperScan;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication@MapperScan("com.zzuli.mapper")//mapper扫描器publicclassAppleunlockManageApplication{publicstaticvoidmain(String[] args){SpringApplication.run(AppleunlockManageApplication.class, args);}}
效果展示
注意:测试时要打开
redis
,数据库中的密码必须是加密后的
可以使用一下方法进行加密,
passwordEncoder
是
SecurityConfig
中已经注入的
@ResourceprivatePasswordEncoder passwordEncoder;String encode = passwordEncoder.encode("123456");System.out.println(encode);
登录接口测试
版权归原作者 韭菜盖饭 所有, 如有侵权,请联系我们删除。