草庐IT

Spring Security(6)

湘王 2023-04-16 原文

您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~

 

Spring Security使用MySQL保存cookie记录虽然方便,但是目前更多的主流互联网应用都是用NoSQL来保存非业务数据的,Spring Security也应该可以实现这个功能。之前Spring Security官方并不支持使用NoSQL来保存cookie,但这个问题对于一个爱钻研的码农来说应该只是个小CASE——毕竟只要有代码,就没有搞不定的问题——JdbcTokenRepositoryImpl的启发,查看其源码,可以发现JdbcDaoSupport只是用来提供数据源,无实际意义,PersistentTokenRepository才是要实现的接口。

JdbcTokenRepositoryImpl的源码非常简单,看懂了就能照着写出Mongo的实现。题外话:阅读源码是个能够很快提高开发能力的捷径,如Spring框架、Spark源码等等。

下面就来开始咱们的NoSQL改造DIY。

首先安装并运行mongodb(我用的是mongodb-4.2.6),可以是虚拟机,也可以是Docker。

再修改项目的pom.xml文件,增加mongodb依赖:

 

 

 

 

通过模仿JdbcDaoSupport,来自定义自己的MongoDaoSupport:

/**
 * MongoDaoSupport
 *
 * @author 湘王
 */
@Component
public class MongoDaoSupport<T> {
    @Autowired
    private MongoTemplate mongoTemplate;

    // 插入数据
    public boolean insert(PersistentRememberMeToken token) {
        if (Objects.isNull(token)) {
            return false;
        }

        Object object = mongoTemplate.save(token);
        if (Objects.nonNull(object)) {
            return true;
        }

        return false;
    }
}

 

 

然后再在MongoDaoSupport中增加两个重要的方法,让它支持Mongodb:

    // 查询数据
    public PersistentRememberMeToken getTokenBySeries(String series) {
//        // 如果是通过字符串方式诸葛插入字段值,那么通过mongoTemplate.findOne()得到的就是一个LinkedHashMap
//        LinkedHashMap<String, String> map = (LinkedHashMap<String, String>) mongoTemplate
//                .findOne(query, Object.class, "collectionName");
//        return new PersistentRememberMeToken(map.get("username"), map.get("series"),
//                map.get("tokenValue"), DateUtils.format()map.get("date"));
        Query query = new Query(Criteria.where("series").is(series));
//        // 这里原路返回PersistentRememberMeToken对象,不会是LinkedHashMap
//        Object object = mongoTemplate.findOne(query, PersistentRememberMeToken.class);
//        return (PersistentRememberMeToken) obejct;
        return mongoTemplate.findOne(query, PersistentRememberMeToken.class);
    }

    // 更新数据
    public boolean updateToken(String series, String tokenValue, Date lastUsed) {
        Query query = new Query(Criteria.where("series").is(series));
        Update update = new Update();
        update.set("tokenValue", tokenValue);
        update.set("date", lastUsed);
//        // 这里不能用DateUtils.parse(new Date()),否则getTokenBySeries()方法会抛出非法参数异常
//        update.set("date", DateUtils.parse(new Date()));
        Object object = mongoTemplate.updateMulti(query, update, PersistentRememberMeToken.class);
        if (Objects.nonNull(object)) {
            return true;
        }
        return false;
    }

 

 

然后再定义MongoTokenRepositoryImpl:

/**
 * 自定义实现token持久化到mongodb
 *
 * @author 湘王
 */
public class MongoTokenRepositoryImpl implements PersistentTokenRepository {
    @Autowired
    private MongoDaoSupport<PersistentRememberMeToken> mongoDaoSupport;

    @Override
    public void createNewToken(PersistentRememberMeToken token) {
        mongoDaoSupport.insert(token);
    }

    @Override
    public void updateToken(String series, String tokenValue, Date lastUsed) {
        mongoDaoSupport.updateToken(series, tokenValue, lastUsed);
    }

    @Override
    public PersistentRememberMeToken getTokenForSeries(String series) {
        return mongoDaoSupport.getTokenBySeries(series);
    }

    @Override
    public void removeUserTokens(String username) {
    }
}

 

 

接着在WebSecurityConfiguration中用自定义的MongoTokenRepositoryImpl代替JdbcTokenRepositoryImpl:

// NoSQL方式实现记住我
@Bean
public PersistentTokenRepository persistentTokenRepository() {
    // 自定义mongo方式实现
    MongoTokenRepositoryImpl mongoTokenRepository = new MongoTokenRepositoryImpl();
    return mongoTokenRepository;
}

 

 

或者就直接(需要通过@Service注解注入):

 

 

 

 

运行postman测试,可以看到通过MongoDB实现了对cookie信息的存储与修改。

如果mongodb中多出了_class字段,可以加上额外的配置:

/**
 * 去除_class字段
 *
 * @author 湘王
 */
@Configuration
public class MongoConfiguration implements InitializingBean {
    @Autowired
    @Lazy
    private MappingMongoConverter mappingMongoConverter;

    @Override
    public void afterPropertiesSet() {
        mappingMongoConverter
                .setTypeMapper(new DefaultMongoTypeMapper(null));
    }
}

 

 

多次运行可发现访问记录值的规律:

1、同一用户会有多条访问记录

如果每次都明确执行login方法,那么每次都会产生不同的记录,否则只会更新同一条记录的tokenValue和date值;

token有效且未执行login方法,那么将更新最后一次产生的记录的tokenValue和date值。

2、这说明token条数是与login方法执行次数一一对应的;

3、只要token不失效,仅更新同一条记录series的token值。

 

访问数据记录:

 

 

 

不管是Mongodb还是别的NoSQL,比如Redis,原理都是一样的。

 

 


 

 

感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~

 

有关Spring Security(6)的更多相关文章

  1. Spring Security详细讲解(JWT+SpringSecurity登入案例) - 2

    本篇博文目录:一.SpringSecurity简介1.SpringSecurity2.SpringSecurity相关概念二.认证和授权1.认证(1)使用SpringSecurity进行简单的认证(SpringBoot项目中)(2)SpringSecurity的原理(3)SpringSecurity核心类(4)认证登入案例(JWT+SpringSecurity实现登入案例)2.授权(1)加入权限到Authentication中(2)SecurityConfig配置文件中开启注解权限配置(3)给接口中的方法添加访问权限(4)用户权限表的建立3.自定义失败处理(1)创建异常处理类(2)配置移除处理

  2. SpringSecurity 源码理解及使用(三) - 2

    目录springSecurity授权权限管理策略基于url的权限管理基于方法的权限管理将url权限管理设为动态会话管理会话并发管理会话失效处理禁止再次登录会话共享源码分析CSRF跨站请求伪造开启CSRF防御传统web开发前后端分离开启CSRF防护csrf防御过程CORS跨域问题springBoot解决跨域的三种方式springSecurity解决跨域springSecurity授权认证与授权解耦授权:据系统提前设置好的规则,给用户分配可以访问某一个资源的权限,用户根据自己所具有权限,去执行相应操作。GrantedAuthority应该如何理解呢?是角色还是权限?权限是具体一些操作,角色是一些权

  3. 【解决】分析SpringSecurity访问请求权限不足AccessDeniedException问题 - 2

    问题描述在做项目的时候,使用SpringSecurity配置完系统的访问权限时,进行测试的时候,发现明明携带了访问该路径需要的权限标志,会一直提示说我们权限不足。这里我配置了AccessDeniedHandler,当SpringSecurity判断我们权限不足时,会抛出AccessDeniedException异常,然后执行AccessDeniedHandler中我们重写的的handle方法。解决实在想不出原因的时候,我开始着手从源码去探究报错的原因,于是我从网上找来了这张图,授权测试流程:如图所示,首页请求先会进入FilterSecurityInterceptor过滤器,将它作为断点的入口。

  4. SpringBoot SpringSecurity 介绍(基于内存的验证) - 2

    SpringBoot集成SpringSecurity+MySQL+JWT附源码,废话不多直接盘SpringBoot已经为用户采用默认配置,只需要引入pom依赖就能快速启动SpringSecurity。目的:验证请求用户的身份,提供安全访问优势:基于Spring,配置方便,减少大量代码内置访问控制方法permitAll()表示所匹配的URL任何人都允许访问。authenticated()表示所匹配的URL都需要被认证才能访问。anonymous()表示可以匿名访问匹配的URL。和permitAll()效果类似,只是设置为anonymous()的url会执行filter链中denyAll()表示所

  5. SpringSecurity+GateWay网关+OAuth2鉴权,前后端分离模式,两种验证模式,入门级教程 - 2

    说明SpringSecurityOAuth2单点登录昨天我发了一个单点登录版本的验证博客,到今天早上我再研究了一下,发现了一些问题:昨天那个单点登录是在每个模块的基础上做的,也就是说如果你想让每个模块都如认证中心认证,就要在每个模块里进行相关配置,这还不是最紧要的,你要想想,因为我们是通过注解的方式在对应的方法鉴权,这样的话就会导致我们每次访问这个方法的时候就要去认证中心请求一次,也就是鉴权一次,那么整个系统模块又多,路径又多,认证中心肯定是吃不消的啊.所以在这个基础上,就需要去将认证中心在第一次认证产生的token,交给前端,然后在GateWay里进行一个token的验证,这样子就避免我们每

  6. SpringSecurity +oauth2获取当前登录用户(二) - 2

    特别注意:以下内容如果访问失败或有其他疑问,可先学习:SpringSecurity+oauth2+JWT实现统一授权和认证及项目搭建(一)1获取当前用户的信息代码为:Objectprincipal=SecurityContextHolder.getContext().getAuthentication().getPrincipal();但是,通过运行会发现principal的值只是用户名,没有用户信息,通过去看源码,才发现问题所在,以下是源码:源码类:DefaultUserAuthenticationConverter.java通过源码分析,发现这里的map只存储用户名,对此,如果要获取用户,

  7. 史诗级的SpringSecurity的认证授权的相关概念及流程讲解!!! - 2

    文章目录前言一、SpringSecurity简介二、Shiro和Security的对比2.1Shiro的特点2.2Security的特点2.3二者的相同点三、Security实现权限四、用户认证流程4.1认证接口分析前言Web应用的开发,安全是至关重要的,选择使用SpringSecurity是目前来说较为正确的选择。SpringSecurity框架起源于2003年年底acegi系统,起因是Spring开发者邮件列表中的一个问题,有人提问是否考虑提供一个基于Spring的安全实现。基于SpringBoot+MP+Redis+Vue实现的前后端分离的权限管理系统:https://gitee.com

  8. SpringSecurity的配置 - 2

    一、SpringSecurity的功能简单介绍(1)简介SpringSecurity是针对Spring项目的安全框架,也是SpringBoot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入spring-boot-starter-security模块,进行少量的配置,即可实现强大的安全管理!    主要的几个类:webSecurityConfigurerAdapter:自定义Security策略AuthenticationManagerBuilder:自定义的认证策略@EnableWebSecurity:开启WebSecurity模式    Spring

  9. SpringSecurity安全框架学习——@PreAuthorize的实现原理 - 2

    SpringSecurity安全框架学习——@PreAuthorize的实现原理@PreAuthorize@EnableMethodSecurityMethodSecuritySelectorPrePostMethodSecurityConfiguration@PreAuthorize首先我们打开@PreAuthorize注解的源码,然后按住Ctrl并单击PreAuthorize,可以看到在EnableMethodSecurity注解中有引用(本文使用IDEA,后续不再复述)@EnableMethodSecurity查看EnableMethodSecurity源码,可以到,其引用了Method

  10. springboot整合springsecurity+oauth2.0密码授权模式 - 2

    springboot整合springsecurity+oauth2.0本文采用的springboot去整合springsecurity,采用oauth2.0授权认证,使用jwt对token增强。本文仅为学习记录,如有不足多谢提出。OAuth2简介OAuth2.0是用于授权的行业标准协议。OAuth2.0为简化客户端开发提供了特定的授权流,包括Web应用、桌面应用、移动端应用等。OAuth2相关名词解释Resourceowner(资源拥有者):拥有该资源的最终用户,他有访问资源的账号密码;Resourceserver(资源服务器):拥有受保护资源的服务器,如果请求包含正确的访问令牌,可以访问资源

随机推荐