zoukankan      html  css  js  c++  java
  • (转)Spring Security 之Session管理配置

    出处:https://www.cnblogs.com/jonban/p/session.html

    废话不多说,直接上代码。示例如下:

    1.   新建Maven项目  session

    2.   pom.xml

    复制代码
    <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 
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.java</groupId>
        <artifactId>session</artifactId>
        <version>1.0.0</version>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.5.RELEASE</version>
        </parent>
    
    
        <dependencies>
    
            <!-- Spring Boot -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-oauth2</artifactId>
                <version>2.0.0.RELEASE</version>
            </dependency>
    
    
            <!-- 热部署 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>springloaded</artifactId>
                <version>1.2.8.RELEASE</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>provided</scope>
            </dependency>
    
        </dependencies>
    
        <build>
            <finalName>${project.artifactId}</finalName>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
    
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <executions>
                        <execution>
                            <goals>
                                <goal>repackage</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </project>
    复制代码

    3.   ResponseUtils.java

    复制代码
    package javax.utils;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    import java.net.URLEncoder;
    
    import javax.servlet.http.HttpServletResponse;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    /**
     * HTTP 输出响应内容工具类
     * 
     * @author Logan
     * @createDate 2019-02-13
     * @version 1.0.0
     *
     */
    public class ResponseUtils {
    
        /**
         * 发送HTTP响应信息
         * 
         * @param response HTTP响应对象
         * @param message 信息内容
         * @throws IOException 抛出异常,由调用者捕获处理
         */
        public static void write(HttpServletResponse response, String message) throws IOException {
            response.setContentType("text/html;charset=UTF-8");
    
            try (
                    PrintWriter writer = response.getWriter();
            ) {
                writer.write(message);
                writer.flush();
            }
        }
    
        /**
         * 发送HTTP响应信息,JSON格式
         * 
         * @param response HTTP响应对象
         * @param message 输出对象
         * @throws IOException 抛出异常,由调用者捕获处理
         */
        public static void write(HttpServletResponse response, Object message) throws IOException {
            response.setContentType("application/json;charset=UTF-8");
            ObjectMapper mapper = new ObjectMapper();
    
            try (
                    PrintWriter writer = response.getWriter();
            ) {
                writer.write(mapper.writeValueAsString(message));
                writer.flush();
            }
        }
    
        /**
         * 下载文件
         * 
         * @param response HTTP响应对象
         * @param message 输出对象
         * @throws IOException 抛出异常,由调用者捕获处理
         */
        public static void write(HttpServletResponse response, File file) throws IOException {
            String fileName = file.getName();
            try (
                    OutputStream out = response.getOutputStream();
                    FileInputStream in = new FileInputStream(file);
            ) {
    
                // 对文件名进行URL转义,防止中文乱码
                fileName = URLEncoder.encode(fileName, "UTF-8");
    
                // 空格用URLEncoder.encode转义后会变成"+",所以要替换成"%20",浏览器会解码回空格
                fileName = fileName.replace("+", "%20");
    
                // "+"用URLEncoder.encode转义后会变成"%2B",所以要替换成"+",浏览器不对"+"进行解码
                fileName = fileName.replace("%2B", "+");
                response.setContentType("application/x-msdownload;charset=UTF-8");
                response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
    
                byte[] bytes = new byte[4096];
                int len = -1;
                while ((len = in.read(bytes)) != -1) {
                    out.write(bytes, 0, len);
                }
                out.flush();
            }
        }
    
    }
    复制代码

    4.   SessionStarter.java

    复制代码
    package com.java;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    /**
     * <blockquote><pre>
     * 
     * 主启动类
     * 
     * </pre></blockquote>
     * 
     * @author Logan
     *
     */
    @SpringBootApplication
    public class SessionStarter {
    
        public static void main(String[] args) {
            SpringApplication.run(SessionStarter.class, args);
        }
    
    }
    复制代码

    5.   SessionInformationExpiredStrategyImpl.java

    复制代码
    package com.java.session;
    
    import java.io.IOException;
    
    import javax.servlet.ServletException;
    import javax.utils.ResponseUtils;
    
    import org.springframework.security.web.session.SessionInformationExpiredEvent;
    import org.springframework.security.web.session.SessionInformationExpiredStrategy;
    
    /**
     * Session过期处理策略
     * 
     * @author Logan
     * @createDate 2019-02-13
     * @version 1.0.0
     *
     */
    public class SessionInformationExpiredStrategyImpl implements SessionInformationExpiredStrategy {
    
        @Override
        public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
    
            ResponseUtils.write(event.getResponse(), "你的账号在另一地点被登录");
        }
    
    }
    复制代码

    6.   ApplicationContextConfig.java

    复制代码
    package com.java.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    /**
     * 配置文件类
     * 
     * @author Logan
     * @createDate 2019-02-13
     * @version 1.0.0
     *
     */
    @Configuration
    public class ApplicationContextConfig {
    
        /**
         * 配置密码编码器,Spring Security 5.X必须配置,否则登录时报空指针异常
         */
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
    }
    复制代码

    7.   LoginConfig.java

    复制代码
    package com.java.config;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    
    import com.java.session.SessionInformationExpiredStrategyImpl;
    
    /**
     * 登录相关配置
     * 
     * @author Logan
     * @createDate 2019-02-13
     * @version 1.0.0
     *
     */
    @Configuration
    public class LoginConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
    
            http.authorizeRequests()
    
                    // 设置不需要授权的请求
                    .antMatchers("/js/*", "/login.html").permitAll()
    
                    // 其它任何请求都需要验证权限
                    .anyRequest().authenticated()
    
                    // 设置自定义表单登录页面
                    .and().formLogin().loginPage("/login.html")
    
                    // 设置登录验证请求地址为自定义登录页配置action ("/login/form")
                    .loginProcessingUrl("/login/form")
    
                    // 设置默认登录成功跳转页面
                    .defaultSuccessUrl("/main.html")
    
                    /* session 管理 */
                    .and().sessionManagement()
    
                    // 设置Session失效跳转页面
                    .invalidSessionUrl("/login.html")
    
                    // 设置最大Session数为1
                    .maximumSessions(1)
    
                    // 设置Session过期处理策略
                    .expiredSessionStrategy(new SessionInformationExpiredStrategyImpl()).and()
    
                    // 暂时停用csrf,否则会影响验证
                    .and().csrf().disable();
        }
    
    }
    复制代码

    8.   SecurityUserDetailsService.java

    复制代码
    package com.java.service;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.authority.AuthorityUtils;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.stereotype.Component;
    
    /**
     * UserDetailsService实现类
     * 
     * @author Logan
     * @createDate 2019-02-13
     * @version 1.0.0
     *
     */
    @Component
    public class SecurityUserDetailsService implements UserDetailsService {
    
        @Autowired
        private PasswordEncoder passwordEncoder;
    
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    
            // 数据库存储密码为加密后的密文(明文为123456)
            String password = passwordEncoder.encode("123456");
    
            System.out.println("username: " + username);
            System.out.println("password: " + password);
    
            // 模拟查询数据库,获取属于Admin和Normal角色的用户
            User user = new User(username, password, AuthorityUtils.commaSeparatedStringToAuthorityList("Admin,Normal"));
    
            return user;
        }
    
    }
    复制代码

    9.   静态资源文件如下

    static/login.html

    static/main.html

    10.  login.html

    复制代码
    <!DOCTYPE html>
    <html>
    
        <head>
            <title>登录</title>
            <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
        </head>
    
        <body>
    
            <!--登录框-->
            <div align="center">
                <h2>用户自定义登录页面</h2>
                <fieldset style=" 300px;">
                    <legend>登录框</legend>
                    <form action="/login/form" method="post">
                        <table>
                            <tr>
                                <th>用户名:</th>
                                <td><input name="username" value="Logan" /> </td>
                            </tr>
                            <tr>
                                <th>密码:</th>
                                <td><input type="password" name="password" value="123456" /> </td>
                            </tr>
                            <tr>
                                <th></th>
                                <td></td>
                            </tr>
                            <tr>
                                <td colspan="2" align="center"><button type="submit">登录</button></td>
                            </tr>
                        </table>
                    </form>
                </fieldset>
    
            </div>
    
        </body>
    
    </html>
    复制代码

    11.   main.html

    复制代码
    <html>
    
        <head>
            <title>首页</title>
            <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
            <script>
                window.onclick = function() {
                    window.open("http://www.cnblogs.com/jonban/");
                }
            </script>
        </head>
    
        <body style="text-align: center;">
            <h1><span style="text-align:center;color:purple;cursor: pointer;">Designed by Logan.</span></h1>
            <canvas id="c"></canvas>
            <script>
                var b = document.body;
                var c = document.getElementsByTagName('canvas')[0];
                var a = c.getContext('2d');
                document.body.clientWidth;
            </script>
    
            <script>
                with(m = Math)
                C = cos, S = sin, P = pow, R = random;
                c.width = c.height = f = 613;
                h = -250;
    
                function p(a, b, c) {
                    if(c > 60)
                        return [S(a * 7) * (13 + 5 / (.2 + P(b * 4, 4))) - S(b) * 50,
                            b * f + 50,
                            625 + C(a * 7) * (13 + 5 / (.2 + P(b * 4, 4))) + b * 400,
                            a * 1 - b / 2, a
                        ];
                    A = a * 2 - 1;
                    B = b * 2 - 1;
                    if(A * A + B * B < 1) {
                        if(c > 37) {
                            n = (j = c & 1) ? 6 : 4;
                            o = .5 / (a + .01) + C(b * 125) * 3 - a * 300;
                            w = b * h;
                            return [o * C(n) + w * S(n) + j * 610 - 390, o * S(n) - w * C(n) + 550 - j * 350, 1180 + C(B + A) * 99 - j * 300, .4 - a * .1 + P(1 - B * B, -h * 6) * .15 - a * b * .4 + C(a + b) / 5 + P(C((o * (a + 1) + (B > 0 ? w : -w)) / 25), 30) * .1 * (1 - B * B), o / 1e3 + .7 - o * w * 3e-6]
                        }
                        if(c > 32) {
                            c = c * 1.16 - .15;
                            o = a * 45 - 20;
                            w = b * b * h;
                            z = o * S(c) + w * C(c) + 620;
                            return [o * C(c) - w * S(c), 28 + C(B * .5) * 99 - b * b * b * 60 - z / 2 - h, z, (b * b * .3 + P((1 - (A * A)), 7) * .15 + .3) * b, b * .7]
                        }
                        o = A * (2 - b) * (80 - c * 2);
                        w = 99 - C(A) * 120 - C(b) * (-h - c * 4.9) + C(P(1 - b, 7)) * 50 + c * 2;
                        z = o * S(c) + w * C(c) + 700;
                        return [o * C(c) - w * S(c), B * 99 - C(P(b, 7)) * 50 - c / 3 - z / 1.35 + 450, z, (1 - b / 1.2) * .9 + a * .1, P((1 - b), 20) / 4 + .05]
                    }
                }
                setInterval('for(i=0;i<1e4;i++)if(s=p(R(),R(),i%46/.74)){z=s[2];x=~~(s[0]*f/z-h);y=~~(s[1]*f/z-h);if(!m[q=y*f+x]|m[q]>z)m[q]=z,a.fillStyle="rgb("+~(s[3]*h)+","+~(s[4]*h)+","+~(s[3]*s[3]*-80)+")",a.fillRect(x,y,1,1)}', 0)
            </script>
        </body>
    
    </html>
    复制代码

    12.   运行SessionStarter.java ,启动项目

    浏览器输入 http://localhost:8080/main.html

    自动跳转到登录页面

    输入如下信息:

    User:Logan

    Password:123456

     单击【登录】按钮,自动跳转到首页。

    换用其它浏览器再次访问 http://localhost:8080/main.html

    输入相同用户信息: 

    User:Logan

    Password:123456

    单击【登录】按钮,自动跳转到首页。

    刷新第一个浏览器,提示

    你的账号在另一地点被登录

     再次刷新,跳转到登录页面。

    Session配置生效!

    .

  • 相关阅读:
    vue笔记-inheritAttrs及$attr表示含义(一)
    Springboot项目使用junit-test(@Test)报错原因汇总
    @Configuration的使用
    Spring-RabbitMQ实现商品的同步(后台系统)
    RabbitMQ持久化和非持久化
    spring-AMQP-RabbitMQ
    RabbitMQ的5种模式
    RabbitMQ消息队列+安装+工具介绍
    Mina整体体系结构分析
    Mina入门级客户端程序实现telnet程序
  • 原文地址:https://www.cnblogs.com/telwanggs/p/12620223.html
Copyright © 2011-2022 走看看