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查询信息

相关推荐
Chrikk10 分钟前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*12 分钟前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue13 分钟前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man15 分钟前
【go从零单排】go语言中的指针
开发语言·后端·golang
测开小菜鸟16 分钟前
使用python向钉钉群聊发送消息
java·python·钉钉
P.H. Infinity1 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天1 小时前
java的threadlocal为何内存泄漏
java
caridle1 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
萧鼎2 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
学地理的小胖砸2 小时前
【一些关于Python的信息和帮助】
开发语言·python