在文章: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查询信息