SpringBoot整合SpringSecurit(二)通过token进行访问

在文章:SpringBoot整合SpringSecurit(一)实现ajax的登录、退出、权限校验-CSDN博客

里面,使用的session的方式进行保存用户信息的,这一篇文章就是使用token的方式。

在其上进行的改造,可以先看SpringBoot整合SpringSecurit(一)实现ajax的登录、退出、权限校验-CSDN博客,再看这个就比较好了。

1、新建过滤器,将通过token查询到的用户信息存入到security中

package com.example.springboot.security.demo.filter;

import com.example.springboot.security.demo.controller.LoginController;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

/**
 * 将用户信息存入security中
 */
@Slf4j
@Component
public class AuthFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 比如请求头中有个header叫token,放置了认证后的请求头
        String token = request.getHeader("token");
        log.info("用户token:{}", token);
        if (StringUtils.hasText(token)) {
            // 验证token是否已经登录了的用户的token,用户的token临时放在了LoginController
            UserDetails userDetails = LoginController.TOKEN_USERNAME.get(token);
            if (Objects.nonNull(userDetails)) {
                // 有,表示token是对的,设置线程上下文认证信息,然后访问其他资源时,security就会放行
                UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            }
        }
        filterChain.doFilter(request, response);
    }
}

2、修改security的配置

/**
     * 密码加密方式
     * //使用BCrypt进行密码加密校验
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


/**
     * 2.0配置,security通过token访问,不通过session访问
     * @param http
     * @throws Exception
     */
    @Resource
    private AuthFilter authFilter;
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();//禁用CSRF控制,即spring security不再限制CSRF,即跨越访问

        http
                .authorizeRequests()
                .antMatchers("/static/**").permitAll()//不需要登录认证就可以访问,静态资源等不需要验证
                .antMatchers("/login").permitAll() // 允许任何人访问登录接口
                .anyRequest().authenticated();//其他路径必须验证身份

        http
                .sessionManagement(sessionManager -> sessionManager.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); //不再管理session

        // 设置用户访问前filter
        http.addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class);

        http
                .formLogin()
                .loginPage("/login-view.html")//自定义登录页面路径,加载登录的html页面
                .successHandler(userLoginAuthenticationSuccessHandler)//验证成功处理
                .failureHandler(userLoginAuthenticationFailureHandler)//验证失败处理
                .permitAll();//登录页面无需设置验证

        http
                .logout()
                .logoutUrl("/logout")//登出路径
                .logoutSuccessHandler(userLogoutSuccessHandler)//登出处理
                .permitAll()//不需要身份认证
                .and()
                .exceptionHandling().accessDeniedHandler(userAuthenticationAccessDeniedHandler);//无权限时的处理
    }

3、修改登录方法,后端获取到账号、密码后,根据账号,查询到用户信息,在校验密码,如果密码成功,就生成token,并且把token放在内存或者redis中就完成了

/**
     * 简单的存放用户登录认证成功信息的地方
     */
    public final static Map<String, UserDetails> TOKEN_USERNAME = new HashMap<>();
    @Resource
    private UserDetailsServiceImpl userDetailsService;
    /**
     * SecurityConfig中配置的密码加密
     */
    @Resource
    private PasswordEncoder passwordEncoder;

    /**
     * 登录认证,获得token
     * @param account 登录账号
     * @param password 密码
     * @return 认证token
     */
    @ResponseBody
    @PostMapping("/login")
    public JsonData login(String account, String password) {
        JsonData jsonData = null;
        //根据账号,查询用户信息
        UserDetails userDetails = userDetailsService.loadUserByUsername(account);
        if (userDetails == null) {
            jsonData = new JsonData(401,"用户名不存在");
            return jsonData;
        }
        //密码校验
        if(!passwordEncoder.matches(password,userDetails.getPassword())) {
            jsonData = new JsonData(401,"用户或密码错误");
            return jsonData;
        }
        // 认证成功发个token,返回给前端
        String token = UUID.randomUUID().toString();
        TOKEN_USERNAME.put(token, userDetails);
        System.out.println("token:" + token);
        jsonData = new JsonData(200,token);
        return jsonData;
    }

4、测试

4.1、获取token

4.2、通过token查询信息

相关推荐
web136885658711 分钟前
rust教程 第一章 —— 初识rust
开发语言·后端·rust
songroom2 分钟前
Rust : tokio中select!
开发语言·后端·rust
dubochao_xinxi4 分钟前
QT5 在某些系统出现qt.qpa.xcb: could not connect
开发语言·qt
blueman88886 分钟前
QWidget应用封装为qt插件,供其他qt应用调用
开发语言·qt
qincjun8 分钟前
Qt仿音乐播放器:设置窗口、部件属性
开发语言·qt
编码小哥17 分钟前
C++线程同步和互斥
开发语言·c++
qincjun19 分钟前
Qt仿音乐播放器:动画类
开发语言·qt
L.S.V.28 分钟前
Java 溯本求源之基础(三十)——封装,继承与多态
java·开发语言
码农爱java29 分钟前
设计模式--装饰器模式【结构型模式】
java·设计模式·面试·装饰器模式·原理·23 中设计模式
游客52035 分钟前
设计模式-创建型-工厂方法模式
开发语言·python·设计模式·工厂方法模式