【Spring Security】安全框架学习(三)

2.3 解决问题

2.3.1 思路分析

实际上分了两部分,一个是登陆一个是校验。

登陆:①自定义登陆的接口,调用providerManager的方法进行认证

​ 如果认证通过,则生成JWT;把用户信息缓存到redis中。

​ ②自定义UserDetailService,实现查询数据库

校验:①定义JWT认证过滤器,获取token并解析token

​ ②获取token中的userId,从redis中获取用户信息,存入SecurityContextHolder中。 在这里插入图片描述

思考:Jwt认证过滤器中从获取到了userId后,怎么获取到完整的用户信息?

在这里插入图片描述

2.3.2 准备工作

①添加依赖

<!--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>

②添加Redis相关配置

package utils;

import ...

/**
 * Redis使用FastJson序列化
 * @author sg
 */
public class FastJsonRedisSerializer<T> implements RedisSerializer<T>{
    public static fina1 Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
	private Class<T> clazz;
	static{
		ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
	}
	public FastJsonRedisSerializer(Class<T> clazz){	
		super();
		this.clazz = clazz;
	}
    @override
	public byte[] serialize(T t) throws SerializationException{
        if (t == nu11) {
            return new byte[0];
        }
        return JSON.toJSONString(t,SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }
    
	@override
	public T deserialize(byte[] bytes) throws SerializationException{
        if (bytes == nul1 || bytes.length <= 0) {
            return nu11;
        }
        String str =new String(bytes, DEFAULT_CHARSET);
		return JSoN.parseobject(str, clazz);
    }

	protected JavaType getJavaType(Class<?> clazz) {
    	return TypeFactory.defaultInstance().constructType(clazz);
	}

}


package config;

import ...

@configuration
public class RedisConfig {
	@Bean
	@SuppressWarnings(value = { "unchecked", "rawtypes" })
	public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<object, Object> template = new RedisTemplate<>();
		template.setConnectionFactory(connectionFactory);
		FastJsonRedisSerializer serializer = new 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 template;
    }
}

③响应类

package domain;

import ...

@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResponseResult<T> {
	/**
	 * 状态码
	 */
	private Integer code;
	/**
	 * 提示信息,如果有错误时,前端可以获取该字段进行提示
	 */
	private String msg;
	/**
	 * 查询到的结果数据,
	 */
	private T data;
    
	public ResponseResult(Integer code, String msg) {
		this.code = code;
		this.msg =msg;
    } 
	public ResponseResult(Integer code, T data) {
		this.code = code;
		this.data = data;
    }
    public Integer getCode() {
		return code;
    }
	public void setCode(Integer code) {
		this.code = code;
    }
	public String getMsg() {
		return msg;
    }

	public void setMsg(String msg) {
		this.msg =msg;
    }
	public T getData() {
		return data;
    }
	public void setData(T data) {
		this.data = data;
    }
	public ResponseResult(Integer code, String msg, T data) {
		this.code = code;
		this.msg =msg;
		this.data = data;
    }
}

④工具类

package utils;

import ...

/**
*JWT工具类
*/
public class JwtUtil {
	//有效期为
	pub1ic static final Long JWT_TTL = 60*60*1000L;// 60*60*1000 一个小时
	
    //设置秘钥明文
	public static final String JWT_KEY = "Hello";
	public static String getUUID(){
		String token = UUID.randomUUID().toString().replaceAl1("-","");
    }
	/**
	 * 生成jtw
	 * @param subject token中要存放的数据(json格式)
	 * @return
	 */
	public static String createJWT(String subject) {
		JwtBuilder builder =getJwtBuilder(subject,nul11,getuuID());//设置过期时间
		return builder.compact();
    }
    
    /**
	 * 生成jtw
	 * @param subject token中要存放的数据(json格式)
	 * @param ttlMil1is token超时时间
	 * @return
	 */
	public static String createJWT(String subject, Long ttlMillis) {
		JwtBuilder builder= getJwtBuilder(subject,tt1Mil1is,getUuID());//设置过期时间
		return builder.compact();
    }
    
    private static JwtBuilder getJwtBuilder (string subject, Long tt1Millis, string uuid) {
		SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
		SecretKey secretKey = generalKey();
		long nowMi11is = System.currentTimeMi1lis();
		Date now = new Date(nowMi11is);
		if(tt1Mi11is==nu11) {
			tt1Mi11is=JwtUti1.JWT_TTL;
        }
		long expMillis = nowMillis + ttlMillis;
		Date expDate = new Date(expMillis);
		return Jwts.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
	 */
	public static String createJWT(String id, String subject, Long ttlMillis) {
		JwtBuilder builder= getJwtBuilder(subject,ttlMillis,id)://设置过期时间
		return builder.compact();
    }
    
    public static void main(String[] args) throws Exception {
		String token = "eyJhbGci0iJIUzI1NiJ9.eyJqdGkiOiJjYWM2ZDVhZilmNjVlLTQOMDAtYjcxMiOzYWEwOGIyOTIwYjQiLCJzdWIi0iJzZyIsImlzcyI6InNnIiwiaWFOIjoxNjM4MTA2NzEyLCJleHAi0jE2MzgxMTAzMTJ9.JVsSbkP94wuczb4QryQbAke3ysBDIL5ou8fWsbt_ebg";
		Claims claims = parseJWT(token);
		System.out.println(claims);
    }
	
	/**
	 * 生成加密后的秘钥 secretKey
	 * @return
	 */
	public static SecretKey generalKey() {
		byte[] encodedkey = Base64.getDecoder().decode(JwtUti1.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();
    }

}

package utils;

import ...

@suppresswarnings (value = { "unchecked", "rawtypes" })
@component
public class RedisCache{
    @Autowired
	public RedisTemplate redisTemplate;

	/**
	 * 缓存基本的对象,Integer、String、实体类等
	 * @param key缓存的键值
	 * @param value 缓存的值
	 */
	public <T> void setcacheobject(final string key, final T value)
		redisTemplate.opsForValue().set(key, value);
	}

	/**
	 * 缓存基本的对象,Integer、String、实体类等
	 * @param key 缓存的键值
	 * @param value 缓存的值
	 * @param timeout 时间
	 * @param timeunit 时间颗粒度
	 */
	public <T> void setCacheobject(final string key, final T value, final Integer timeout, final Timeunit timeUnit) {
    	redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
	}

	/**
	 * 设置有效时间
	 *
	 * aparam key Redis键
	 * @param timeout 超时时间
	 * areturn true=设置成功;false=设置失败
	 */
	public boolean expire(final String key, final long timeout){
		return expire(key, timeout, TimeUnit.SECONDS);
	}
	
	/**
	 * 设置有效时间
	 * @param key Redis键
	 * @param timeout 超时时间
	 * @param unit 时间单位
	 * @return true=设置成功;false=设置失败
	 */
	public boolean expire(final string key, final long timeout, final Timeunit unit){
		return redisTemplate.expire(key, timeout, unit);
    }

	/**
	 * 获得缓存的基本对象。
	 * @param key缓存键值
	 * @return缓存键值对应的数据
	 */
	public <T> T getCacheobject(final String key){
		ValueOperations<String, T> operation = redisTemplate.opsForValue();
		return operation.get(key);
    }

	/**
	 * 删除单个对象
	 * @param key
	 */
	public boolean deleteobject(final String key) {
		return redisTemplate.delete(key);
    }
	/**
	 * 删除集合对象
	 * @param collection 多个对象
	 * @return
	 */
	public long deleteobject(final collection collection){
		return redisTemplate.delete(collection);
	}
	/**
	 * 缓存List数据
	 * aparam key缓存的键值
 	 * @param dataList 待缓存的List数据
	 * areturn缓存的对象
	 */
	public <T> long setCachelist(final String key, final List<T> datalist){
    	Long count = redisTemplate.opsForList(O.rightPushA11(key, datalist);
		return count == nul1 ? 0 : count;
	}
                                              
	/**
	 * 获得缓存的1ist对象
	 *
	 * aparam key 缓存的键值
	 * @return缓存键值对应的数据
	 */
	public <T> List<T> getCachelList(final String key){
        return redisTemplate.opsForList().range(key, 0, -1);
    }
		
	/**
	 * 缓存Set
	 * @param key缓存键值
	 * aparam dataset 缓存的数据
	 * @return缓存数据的对象
	 */
	public <T> Boundsetoperations<string, T> setCacheset(final String key, final Set<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(final String key){
        return redisTemplate.opsForSet().members(key);
    }
                                              
	/**
	 * 缓存Map
	 *
	 * @param key
	 * @param dataMap
	 */
	public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
        if (dataMap !=nu11){
			rediTemplate.opsForHash().putAl1(key, dataMap);
		}
    }
                                              
	/**
	 * 获得缓存的Map
	 * @param key
	 * @return
	 */
	public <T> Map<String, T> getCacheMap(final String key){
	 return redisTemplate.opsForHash().entries(key);
    }

	/**
	 * 往Hash中存入数据
	 * @param key Redis键
	 * @param hKey Hash键
	 * @param value 值
	 */
	public <T> void setCacheMapValue(final String key, final String hkey, final T value) {
		redisTemplate.opsForHash().put(key, hkey, value);
    }
                                              
	/**
	 * 获取Hash中的数据
	 * @param key Redis键
	 * @param hKey Hash键
	 * @return Hash中的对象
	 */
	public <T> T getCacheMapValue(final String key, final String hkey) {
		HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
		return opsForHash.get(key, hkey);
    }
    
	/**
	 * 删除Hash中的数据
	 * @param key
	 * @param hkey
	 */
	public void delCacheMapValue(final String key, final String hkey) {
		HashOperations hashOperations = redisTemplate.opsForHash();
		hashoperations.delete(key, hkey);
    }

	/**
	 * 获取多个Hash中的数据
	 * aparamkey Redis键
	 * @param hKeys Hash键集合
	 * @return Hash对象集合
	 */
	public <T> List<T> getMultiCacheMapValue(final String key, final Collection<0bject> hkeys) {
		return redisTemplate.opsForHash().multiGet(key, hkeys);
    }
                                              
    /**
	 * 获得缓存的基本对象列表
	 * @param pattern 字符串前缀
	 * @return对象列表
	 */
	public Collection<String> keys(final String pattern) {
		return redisTemplate.keys(pattern);
    }

}

package utils;

import ...

public class WebUtils
	/**
	 * 将字符串渲染到客户端
	 * aparam response 渲染对象
	 * @param string待渲染的字符串
	 * @return null
	 */
	public static String renderstring(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();
        }
		return null;
	}
}

⑤实体类

package domain;

import ...

/**
* 用户表(user)实体类
*/
@Data
@A11ArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
    
		private static fina1 long serialversionUID = -40356785423868312L;
    
	/**
	 * 主键
	 */
	private Long id;
    
	/**
	 * 用户名
	 */
	private String userName;
    
	/**
	 * 昵称
	 */
	private String nickName;
    
	/**
	 * 密码
	 */
	private String password;
	
    /**
	 * 账号状态(0正常1停用)
	 */
	private String status;
	
    /**
	 * 邮箱
	 */
	private String email;
    
    private String email;
    
    /**
	 * 手机号
	 */
	private String phonenumber;
	
    /**
	 * 用户性别(0男,1女,2未知)
	 */
	private String sex;
	
    /**
	 * 头像
	 */
	private String avatar;
	
    /**
	 * 用户类型(0管理员,1普通用户)
	 */
	private String userType;
	
    /**
	 * 创建人的用户id
	 */
	private Long createBy;
	
    /**
	 * 创建时间
	 */
	private Date createTime;
    
    /**
	 * 更新人
	 */
	private Long updateBy;
	
    /**
	 * 更新时间
	 */
	private Date updateTime;
	
    /**
	 * 删除标志(0代表未删除,1代表已删除)
	 */
	private Integer delFlag;
}


end
  • 作者:dicraft(联系作者)
  • 更新时间:2022-08-27 11:18
  • 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
  • 转载声明:如果是转载栈主转载的文章,请附上原文链接
  • 评论

    新增邮件回复功能,回复将会通过邮件形式提醒,请填写有效的邮件!