springboot +springsecurity+redis 实现登录验证 session 共享

我们知道 springsecurity 是spring 家族中一个安全登录框架 简介的话 大家可以去百度搜索一下 我这就不一一介绍了  主要是懒

废话不多说 直接上代码 需要的pom 文件 我这里用的是redis  +mybatis plus +mysql +springboot +springsecurity+spring-seesion

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--引入 commons-lang,提供基础的\通用的操作和处理 -->
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.4</version>
        </dependency>

        <!--引入 commons-beanutils,提供javaBean操作有关的工具方法 -->
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.3</version>
        </dependency>


        <!--引入 fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.39</version>
        </dependency>

        <!--引入mysql 连接-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatisplus-spring-boot-starter</artifactId>
            <version>1.0.5</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>2.3.3</version>
        </dependency>

        <!-- 权限-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <!-- 引入redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
            <version>2.0.4.RELEASE</version>
        </dependency>



        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!--引入http请求-->
        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.1</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/libs/commons-httpclient-3.1.jar</systemPath>
        </dependency>

        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>3.1</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/libs/commons-codec-1.12.jar</systemPath>
        </dependency>
    </dependencies>

    <profiles>
        <profile>
            <id>test</id>
            <properties>
                <profileActive>test</profileActive>
            </properties>
        </profile>
        <profile>
            <id>stage</id>
            <properties>
                <profileActive>stage</profileActive>
            </properties>
        </profile>
        <profile>
            <id>dev</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <profileActive>dev</profileActive>
            </properties>
        </profile>
    </profiles>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <includeSystemScope>true</includeSystemScope>
                </configuration>
            </plugin>
        </plugins>

        <!--配置不同的环境需要-->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <excludes>
                    <exclude>application.propertits</exclude>
                    <exclude>application-${profileActive}.propertits</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <includes>
                    <include>application.propertits</include>
                    <include>application-${profileActive}.propertits</include>
                    <include>*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>

</project>

1创建一个springboot项目 引入上述pom  文件 

 

我在这里是根据不同的环境 用不同 的配置文件 来

配置文件

#spring.profiles.active=dev
server.port=9998

spring.datasource.url = jdbc:mysql://127.0.0.1/test?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true
serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.username =root
spring.datasource.password =root
spring.datasource.driverClassName = com.mysql.cj.jdbc.Driver



# MyBatis-plus 配置
mybatis-plus.mapper-locations=classpath:/mybatis/*Mapper.xml
mybatis-plus.global-config.id-type=2
mybatis-plus.global-config.field-strategy=2
mybatis-plus.global-config.db-column-underline=true
mybatis-plus.global-config.refresh-mapper=true
mybatis-plus.global-config.logic-delete-value=0
mybatis-plus.global-config.logic-not-delete-value=1
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.configuration.cache-enabled=false

spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.database=1
#spring.redis.password=
spring.redis.poolMaxTotal=50
## 连接池中的最大空闲连接
spring.redis.poolMaxIdle=25
## 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.poolMaxWait=-1

我们需要在application 启动处加入这个注解  这个注解的主要作用就是讲sessio 存到redis 中 从而实现seeion 共享 注解里面的参数 是值 60秒后失效 也就是说你需要重新登录 一般都设置1800 秒 就是30分钟 这里我是用来做测试的

下面是springsecurity 相关代码 首先 创建一个 

WebSecurityConfig 文件
@Configuration
public class WebSecurityConfig  extends WebSecurityConfigurerAdapter{
    @Bean
    public SessionRegistry getSessionRegistry(){
        SessionRegistry sessionRegistry=new SessionRegistryImpl();
        return sessionRegistry;
    }

    @Autowired
    private CustomAccessDeineHandler customAccessDeineHandler;
    @Autowired
    private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
    @Autowired
    private  FailureHandler failureHandler;

    @Autowired
    private  SuccessHandler successHandler;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //String[] passUrls = {"/login.html"};
        /*String[] sendUrls = new String[aProperty.getSignVerifyPath().size()];
        aProperty.getSignVerifyPath().toArray(sendUrls);*/
        //关闭跨站检测
        http.csrf().disable()
                .authorizeRequests()
                //配置免登url
                //.antMatchers(passUrls).permitAll()
                //其余拦截
                .anyRequest().authenticated()
                .and().formLogin()
                //指定登录页的路径
                .loginPage("/login.html")
                //指定自定义form表单请求的路径
                .loginProcessingUrl("/test/form")
                //成功进入一个handler 失败进入一个handler 可以自己定义 只需要  实现相关接口 
                .successHandler(successHandler).failureHandler(failureHandler).permitAll();
        //未登录
        http.exceptionHandling().authenticationEntryPoint(customAuthenticationEntryPoint);
        //无权访问
        http.exceptionHandling().accessDeniedHandler(customAccessDeineHandler);
        //登出清除session
        http.logout().logoutUrl("/logout").invalidateHttpSession(true);

        http.sessionManagement().invalidSessionStrategy(new InvalidSessionStrategy() {
            @Override
            public void onInvalidSessionDetected(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
                httpServletResponse.setContentType("application/json;charset=utf-8");
                PrintWriter out = httpServletResponse.getWriter();
                out.write(JSONObject.toJSONString("身份失效了"));
                out.flush();
                out.close();
            }
        }).maximumSessions(1); //这个地方可以设置一个账号每次能几个人登录同时登录 将maximumSessions 去掉那就是没限制 这个方我默认的是一个账号每次都一个人登录
    }

    @Override
    public void configure(WebSecurity web) {
        //这个免拦截 能免 所有Security 中的拦截器  antMatchers(passUrls).permitAll() 这个免拦截 只是免当前拦截器
        web.ignoring().antMatchers("/login.html");
    }
}

失败进入的FailureHandler

@Component
public class FailureHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        httpServletResponse.setContentType("text/javascript;charset=utf-8");
        PrintWriter out = httpServletResponse.getWriter();
        out.write("登录失败");
        out.flush();
        out.close();
    }
}

成功进入的handle

@Component
public class SuccessHandler  implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        httpServletResponse.setContentType("text/javascript;charset=utf-8");
        PrintWriter out = httpServletResponse.getWriter();
        //这个地方我们可以加入每次登录菜单 的权限给前端返回过去
        out.write("登录成功");
        out.flush();
        out.close();
    }

最后一步 这个方法 

认证是由 AuthenticationManager 来管理的,但是真正进行认证的是 AuthenticationManager 中定义的 AuthenticationProvider。AuthenticationManager 中可以定义有多个 AuthenticationProvider。当我们使用 authentication-provider 元素来定义一个 AuthenticationProvider 时,如果没有指定对应关联的 AuthenticationProvider 对象,Spring Security 默认会使用 DaoAuthenticationProvider。DaoAuthenticationProvider 在进行认证的时候需要一个 UserDetailsService 来获取用户的信息 UserDetails,其中包括用户名、密码和所拥有的权限等。所以如果我们需要改变认证的方式,我们可以实现自己的 AuthenticationProvider;如果需要改变认证的用户信息来源,我们可以实现 UserDetailsService。

我们可以重写这个方法

@Configuration
public class Provider implements AuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;
        HttpServletRequest httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        System.out.println(token.getName()--能获取到登录的账号);
        System.out.println(token.getName());
        System.out.println(token.getCredentials().toString()--能获取到登录的密码);
        System.out.println(token.getCredentials().toString());
/*
        UserDetails userDetails = userDetailsService.loadUserByUsername(token.getName());
*/
        Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        User userDetails = new User("admin", "123", authorities);//这个地方我们可以连接数据库用来对密码进行验证
        if (userDetails == null) {
            throw new UsernameNotFoundException("找不到该用户");
        }
        /*if(!userDetails.getPassword().equals(token.getCredentials().toString()))
        {*/
         if(!userDetails.getPassword().equals(token.getCredentials().toString())){
            throw new BadCredentialsException("密码错误");
         }
        return new UsernamePasswordAuthenticationToken(userDetails,userDetails.getPassword(),userDetails.getAuthorities());
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return  UsernamePasswordAuthenticationToken.class.equals(authentication);
    }
}

UsernamePasswordAuthenticationToken继承AbstractAuthenticationToken实现Authentication
所以当在页面中输入用户名和密码之后首先会进入到UsernamePasswordAuthenticationToken验证(Authentication),
然后生成的Authentication会被交由AuthenticationManager来进行管理
而AuthenticationManager管理一系列的AuthenticationProvider,
而每一个Provider都会通UserDetailsService和UserDetail来返回一个
以UsernamePasswordAuthenticationToken实现的带用户名和密码以及权限的Authentication

这个时候我们就可以看效果了

在不登陆之前我们直接访问接口 

除了上诉配置那个免拦截的 地址 剩下的 任何一个地址都需要登录后才能进行访问

这个适合我们打开登录地址

这个时候我们看登录成功了

再次访问刚才那个接口

然后我们查看reids 中的数据

我们现redis 中已经有session 了 这个时候就代表成功了 然后我们把redis 给清除掉

再次访问

上诉中我不是设置了一个账号只能一个用户登录这个时候我们同样的账号在seeion 没有过期之前换个浏览器登录 然后在刷新原先账号登录的地方 会提示一下错误

意思翻译一下

 

文字描述

参考博客 https://blog.csdn.net/lifeifei2010/article/details/78787558

                https://www.cnblogs.com/softidea/p/6716807.html

               https://blog.csdn.net/u014572215/article/details/80309161

 如有侵权 请联系作者删除。++++++++++++

使用SpringBoot框架结合MyBatis实现Session共享和单点登录可以借助SpringSessionRedis实现。 首先,需要配置SpringSession以使用Redis作为存储方式。可以在SpringBoot的配置文件中添加以下配置: ``` spring.session.store-type=redis spring.session.redis.namespace=spring:session spring.redis.host=127.0.0.1 spring.redis.port=6379 ``` 这样配置后,SpringSession会自动将session信息存储到Redis中。 接着,在登录验证成功后,将用户信息存储到Redis中,并将该用户的唯一标识存储到当前Session的属性中,以便后续验证是否登录。例如: ``` @RequestMapping("/login") public String login(@RequestParam("username") String username, @RequestParam("password") String password, HttpSession session) { // 验证用户名和密码 // ... // 验证通过后,将用户信息存储到Redis中,并设置Session属性 redisTemplate.opsForHash().put("user:" + username, "username", username); session.setAttribute("username", username); return "success"; } ``` 在后续的请求中,可以通过拦截器或过滤器来验证Session是否有效。例如: ``` @Component public class SessionInterceptor implements HandlerInterceptor { @Autowired private RedisTemplate<String, Object> redisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); String username = (String) session.getAttribute("username"); if (StringUtils.isEmpty(username)) { response.sendRedirect("/login"); return false; } String storedUsername = (String) redisTemplate.opsForHash().get("user:" + username, "username"); if (!StringUtils.equals(storedUsername, username)) { response.sendRedirect("/login"); return false; } return true; } } ``` 以上代码片段展示了如何通过拦截器验证Session的有效性。首先从当前Session中获取用户名,如果为空则重定向到登录页面。然后从Redis中获取存储的用户名,如果与当前用户名不匹配,则重定向到登录页面。 这样就实现SpringBoot、MyBatis、SpringSessionRedis共同完成Session共享和单点登录的功能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值