一、使用配置类
说明 本篇只是自己做的笔记 不懂就可以直接私信问
旧版
/**
* spring security配置
*
*/
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)//开启注解支持
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 自定义用户认证逻辑
*/
@Autowired
private UserDetailsService userDetailsService;
/**
* 认证失败处理类
*/
@Autowired
private AuthenticationEntryPointImpl unauthorizedHandler;
/**
* 退出处理类
*/
@Autowired
private LogoutSuccessHandlerImpl logoutSuccessHandler;
/**
* token认证过滤器
*/
@Autowired
private JwtAuthenticationTokenFilter authenticationTokenFilter;
/**
* 跨域过滤器
*/
@Autowired
private CorsFilter corsFilter;
/**
* 解决 无法直接注入 AuthenticationManager
*
* @return
* @throws Exception
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
* 强散列哈希加密实现
*/
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 身份认证接口
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在这里关联数据库和security 见一、3两种配置方法
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
/**
* anyRequest | 匹配所有请求路径
* access | SpringEl表达式结果为true时可以访问
* anonymous | 匿名可以访问
* denyAll | 用户不能访问
* fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录)
* hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问
* hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问
* hasAuthority | 如果有参数,参数表示权限,则其权限可以访问
* hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
* hasRole | 如果有参数,参数表示角色,则其角色可以访问
* permitAll | 用户可以任意访问
* rememberMe | 允许通过remember-me登录的用户访问
* authenticated | 用户登录后可访问
*/
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
// CSRF禁用,因为不使用session
.csrf().disable()
// 认证失败处理类
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
// 基于token,所以不需要session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
// 过滤请求
.authorizeRequests()
// 对于登录login 验证码captchaImage 允许匿名访问
.antMatchers("/login", "/captchaImage").anonymous()
.antMatchers(
HttpMethod.GET,
"/*.html",
"/**/*.html",
"/**/*.css",
"/**/*.js"
).permitAll()
.antMatchers("/profile/**").permitAll()
.antMatchers("/common/download**").permitAll()
.antMatchers("/common/download/resource**").permitAll()
.antMatchers("/swagger-ui.html").permitAll()
.antMatchers("/swagger-resources/**").permitAll()
.antMatchers("/webjars/**").permitAll()
.antMatchers("/*/api-docs").permitAll()
.antMatchers("/druid/**").permitAll()
.antMatchers("/flowable/**").permitAll()
.antMatchers("/socket/**").permitAll()
.antMatchers("/api/common/**").permitAll()
.antMatchers("/api/contract/**").permitAll()
.antMatchers("/api/project/**").permitAll()
.antMatchers("/api/document/**").permitAll()
.antMatchers("/api/purchase/**").permitAll()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated()
.and()
.headers().frameOptions().disable();
httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
// 添加JWT filter
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
// 添加CORS filter
httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);
httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);
}
/***
* 核心过滤器配置方法
* @param web
* @throws Exception
*/
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
}
}
针对常用方法可以看https://blog.csdn.net/qq_31960623/article/details/120829127
新版 此处省略 你记得自己补充完整
@EnableWebSecurity
@Configuration
public class SecurityConfig{
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
//拦截设置
@SneakyThrows
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
return http.antMatcher("").build();
}
//静态资源
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return web -> {
};
}
//身份认证接口
@SneakyThrows
@Bean
public AuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService();
daoAuthenticationProvider.setPasswordEncoder();
return AuthenticationProvider;
}
}
1、HttpSecurity
http.formLogin()//开启表单认证
.loginPage("/toLoginPage")//自定义登录页面 前后端分离无需设置
.loginProcessingUrl("/login")// 登录处理Url 前后端分离无需设置
.usernameParameter("username")//修改表单名字
.passwordParameter("password")//修改表单密码
.successForwardUrl("xx类")// 登录成功后跳转路径 (详情看4)AuthenticationSuccess自动注入后添加进去
.failureHandler("xx类") // 登录失败逻辑处理 (详情看4)
.and().authorizeRequests()//设置安全认证
.antMatchers("/toLoginPage").permitAll()//放行登录页面
.antMatchers("/doLogin").anonymous()//允许未登录的用户进行访问(匿名访问)
.anyRequest().authenticated();//所有请求都需要登录认证才能访问;
.and().rememberMe()//开启记住我功能
.tokenValiditySeconds(1209600)// token失效时间默认2周
.rememberMeParameter("remember-me")// 自定义表单name值 前端传值可以true yes 1 on 都行-->
.apply() //添加配置 继承AbstractHttpConfigurer实现configure(HttpSecurity builder)
.failureHandler(authenticationFailure) //登录失败("见6")
.and()//而且
.authenticationEntryPoint(authenticationEnryPoint) //未登录是的逻辑处理(见8)
.accessDeniedHandler(accessDeny) //权限不足的时候的逻辑处理(见9)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);//关闭session
=========================
//允许跨域
http.cors();
===========安全
// 设置/use
http.authorizeRequests().antMatchers("/user/**").hasRole("ADMIN");
// 设置/user/** 访问需要PRODUCT角色和IP地址为127.0.0.1 .hasAnyRole("PRODUCT,ADMIN")
http.authorizeRequests().antMatchers("/product/**") .access("hasAnyRole('ADMIN,PRODUCT')
and hasIpAddress('127.0.0.1')");
// 设置自定义权限不足信息
http.exceptionHandling().accessDeniedHandler(xxx类);//详情看三中的2、
http..csrf().disable();// 关闭csrf防护
http.headers().frameOptions().sameOrigin();// 允许iframe加载页面
2、WebSecurity
web.ignoring().antMatchers("/css/**", "/images/**", "/js/**", "/favicon.ico");//解决静态资源被拦截的问题
3、AuthenticationManagerBuilder
auth.userDetailsService(userService)// 使用自定义用户认证 userService是看下面二、
.passwordEncoder(bCryptPasswordEncoder());//使用密码加密
========= 或者
auth.authenticationProvider(xx.class);//个人理解此处是可以将加密到方法里(见6)
4、BCryptPasswordEncoder
/**
* 强散列哈希加密实现
*/
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
二、基于数据库实现认证功能
1、UserServiceImpl
实现UserDetailsService接口
@Service
public class UserServiceImpl implements UserService, UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根据名字查询数据库这里只是模仿创建user
User user = User.builder().username("张山").password("@@@@").build();
if (user == null) {
throw new UsernameNotFoundException(username);
}
// 先声明一个权限集合, 因为构造方法里面不能传入null
Collection<? extends GrantedAuthority> authorities = Lists.newArrayList();
//返回对象 默认true不传参的话都是true
//authorities存::new SimpleGrantedAuthority("ROLE_" + 权限名字)
org.springframework.security.core.userdetails.User userDetails = new org.springframework.security.core.userdetails.User(
user.getUsername(),
"{noop}" + user.getPassword(),// {noop}表示不加密认。{bcrypt} 加密认证
true, // 用户是否启用 true 代表启用
true,// 用户是否过期 true 代表未过期
true,// 用户凭据是否过期 true 代表未过
true,// 用户是否锁定 true 代表未锁定
authorities//权限集合
);
return userDetails;
}
}
2、加密
bcrypt****加密后的字符串形如:
$2a 10 10 10wouq9P/HNgvYj2jKtUN8rOJJNRVCWvn1XoWy55N3sCkEHZPo3lyWq
其中$是分割符,无意义;2a是bcrypt加密版本号;10是const的值;而后的前22位是salt值;再
然后的字符串就是密码的密文了;这里的const值即生成salt的迭代次数,默认值是10,推荐值
12。
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
//加密
String encode = bCryptPasswordEncoder.encode("123456");
//验证密码是否正确
boolean matches = bCryptPasswordEncoder.matches("123456", encode);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h84ZA315-1655376031508)(C:\Users\zhk_work\AppData\Roaming\Typora\typora-user-images\image-20220615115212470.png)]
3、获取用户
//3种方式获取
UserDetails userDetails = (UserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//----
@RequestMapping("/loginUser2")
@ResponseBody
public UserDetails getCurrentUser(Authentication authentication) {
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
return userDetails;
}
//----
@RequestMapping("/loginUser3")
@ResponseBody
public UserDetails getCurrentUser(@AuthenticationPrincipal UserDetails userDetails){
return userDetails;
}
4、登录成功和失败
登录成功
实现AuthenticationSuccessHandler接口,并重写onAnthenticationSuccesss()方法.
@Component
public class AuthenticationSuccess implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
//登录成功时返回给前端的数据
ApiResult<Object> result = ApiResult.result(StatusEnum.SUCCESS);
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(JSON.toJSONString(result));
}
}
登录失败
实现AuthenticationFailureHandler接口,并重写onAuthenticationFailure()方法;
package com.jasper.jyunpan.config.security;
import com.alibaba.fastjson.JSON;
import com.jasper.jyunpan.model.dto.ApiResult;
import com.jasper.jyunpan.model.dto.StatusEnum;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author hao
* @date 2022/3/25 15:06
*/
//登录失败返回给前端消息
@Component
public class AuthenticationFailure implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException {
ApiResult result = null;
if(e instanceof UsernameNotFoundException){
result = ApiResult.result(StatusEnum.USERNAME_ERROR);
}else if(e instanceof BadCredentialsException){
result = ApiResult.result(StatusEnum.PASSWORD_ERROR);
}else {
result = ApiResult.fail(e.getMessage());
}
//处理编码方式,防止中文乱码的情况
response.setContentType("text/json;charset=utf-8");
//返回给前台
response.getWriter().write(JSON.toJSONString(result));
}
}
5、退出登录
实现LogoutSuccessHandler
@Component
public class AuthenticationLogout implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
ApiResult<Object> result = ApiResult.result(StatusEnum.SUCCESS);
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(JSON.toJSONString(result));
}
}
6、自定义加密判断
实现AuthenticationProvider
/**
* @author hao
* @date 2022/3/25 15:34
*/
@Component
public class SelfAuthenticationProvider implements AuthenticationProvider {
//此处实现UserDetailsService的那个类
@Autowired
CustomUserDetailsService UserServiceImpl;
@Autowired
BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String account= authentication.getName(); //获取用户名
String password= (String) authentication.getCredentials(); //获取密码
UserDetails userDetails= customUserDetailsService.loadUserByUsername(account);
boolean checkPassword= bCryptPasswordEncoder.matches(password,userDetails.getPassword());
if(!checkPassword){
throw new BadCredentialsException("密码不正确,请重新登录!");
}
return new UsernamePasswordAuthenticationToken(account,password,userDetails.getAuthorities());
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
7、验证码
request.getURI().getPath()获取路径// == login 进行code判断 在网关中判断
8、未登录
实现AuthenticationEntryPoint
@Component
public class AuthenticationEnryPoint implements org.springframework.security.web.AuthenticationEntryPoint {
/**
* 未登录时返回给前端数据
*/
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
ApiResult<Object> result = ApiResult.result(StatusEnum.UNAUTHORIZED);
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(JSON.toJSONString(result));
}
}
三、权限
1、表达式
结合一、1中使用
表达式 | 说明 |
---|---|
permitAll | 指定任何人都允许访问。 |
denyAll | 指定任何人都不允许访问 |
anonymous | 指定匿名用户允许访问。 |
rememberMe | 指定已记住的用户允许访问。 |
authenticated | 指定任何经过身份验证的用户都允许访问,不包含anonymous |
fullyAuthenticated | 指定由经过身份验证的用户允许访问,不包含anonymous和rememberMe |
hasRole(role) | 指定需要特定的角色的用户允许访问, 会自动在角色前面插入’ROLE_’ |
hasAnyRole([role1,role2]) | 指定需要任意一个角色的用户允许访问, 会自动在角色前面插入’ROLE_’ |
hasAuthority(authority) | 色前面插入’ROLE_'指定需要特定的权限的用户允许访问 |
hasIpAddress(ip) | 指定需要特定的IP地址可以访问 |
hasAnyAuthority([authority,authority]) | 指定需要任意一个权限的用户允许访问 |
2、权限不足调用
/**
* 无权访问处理器
* @author hao
* @date 2022/3/25 15:20
*/
@Component
public class AccessDeny implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException {
ApiResult<Object> result = ApiResult.result(StatusEnum.NO_PERMISSION);
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(JSON.toJSONString(result));
}
}
3、自定义权限限制
/*** 自定义授权类 */
@Component
public class MyAuthorizationService {
public boolean check(Authentication authentication, HttpServletRequest request) {
User user = (User) authentication.getPrincipal();
// 获取用户所有权限
Collection<GrantedAuthority> authorities = user.getAuthorities();
// 获取用户名
String username = user.getUsername();
// 如果用户名为admin,则不需要认证
if (username.equalsIgnoreCase("admin")) {
return true;
} else {
// 循环用户的权限, 判断是否有ROLE_ADMIN权限, 有返回true
for (GrantedAuthority authority : authorities) {
String role = authority.getAuthority();
if ("ROLE_ADMIN".equals(role)) {
return true;
}
}
}
return false;
}
}
配置HttpSecurity
//使用自定义Bean授权
http.authorizeRequests().antMatchers("/user/**"). access("@myAuthorizationService.check(authentication,request)");
带有参数的
public boolean check(Authentication authentication, HttpServletRequest request, Integer id) {
if (id > 10) {
return false;
}
return true;
}
配置类 来自你设置你接口的参数{id} 比如 localhost:8080/user/delete/1
//使用自定义Bean授权,并携带路径参数
http.authorizeRequests().antMatchers("/user/delete/{id}"). access("@myAuthorizationService.check(authentication,request,#id)");
4、注解实现权限控制
@PreAuthorize ,
@PostAuthorize ,
@PreFilter ,
@PostFilter
@ProAuthorize : 注解适合进入方法前的权限验证
@PreAuthorize("hasRole('ADMIN')")//需要ADMIN权限
//任意权限都可以
@PreAuthorize("hasAnyAuthority('admin','dept:list')")
===========================================================
@RequestMapping("/update/{id}")
@PreAuthorize("#id<10")
//针对参数权限限定 id<10可以访问
public String update(@PathVariable Integer id, Model model) {
User user = userService.getById(id);
model.addAttribute("user", user);
return "user_update";
}
@PostAuthorize: 在方法执行后再进行权限验证,适合验证带有返回值的权
限, Spring EL 提供返回对象能够在表达式语言中获取到返回对象的 returnObject(返回值user)
/** * 根据ID查询用户 ** @return */
@GetMapping("/{id}")
@ResponseBody
@PostAuthorize("returnObject.username== authentication.principal.username")
//判断查询用户信息是否是当前登录用户信息.否则没有 权限
public User getById(@PathVariable Integer id) {
User user = userService.getById(id);
return user;
}
@PreFilter: 可以用来对集合类型的参数进行过滤, 将不符合条件的元素剔除集合
@GetMapping("/delByIds")
@PreFilter(filterTarget = "ids", value = "filterObject%2==0")
//剔除参数为 基数的值
public String delByIds(@RequestParam(value = "id") List<Integer> ids) {
for (Integer id : ids) {
System.out.println(id);
} return "redirect:/user/findAll";
}
@PostFilter: 可以用来对集合类型的返回值进行过滤, 将不符合条件的元素剔除集合
@RequestMapping("/findAllTOJson")
@ResponseBody
@PostFilter("filterObject.id%2==0")//剔除返回值ID为偶数的值
public List<User> findAllTOJson() {
List<User> userList = userService.list();
return userList;
}
四、跨域
/**
* 解决跨域问题
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
//允许任何域名
.allowedOriginPatterns("*")
//允许任何方法
.allowedMethods("PUT", "DELETE", "GET", "POST", "OPTIONS")
//允许任何头
.allowedHeaders("*")
//暴露头
.exposedHeaders("access-control-allow-headers",
"access-control-allow-methods",
"access-control-allow-origin",
"access-control-max-age",
"X-Frame-Options")
// 是否允许证书(cookies)
.allowCredentials(true)
.maxAge(3600);
}
}
五、流程
登录
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken("账号","密码");
Authentication authenticate = authenticationManager.authenticate(authenticationToken);
//将用户存入上下文中
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
退出登录
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
AuthUser authUser = (AuthUser) authentication.getPrincipal();
//清除上下文
SecurityContextHolder.clearContext();
实体类
@Data
@AllArgsConstructor //全参构造
@NoArgsConstructor //无参构造
public class AuthUser implements UserDetails {
private User user;
// 自行加上就ok
private Collection<? extends GrantedAuthority> authorities;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
//此处也要改
@Override
public String getPassword() {
return user.getPassword();
}
//此处要改
@Override
public String getUsername() {
return user.getUsername();
}
// 账户是否未过期
@Override
public boolean isAccountNonExpired() {
return true;
}
// 账户是否未被锁
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
加数据授权
/**
* 要实现UserDetailsService接口,这个接口是security提供的
*/
@Service(value = "userDetailsService")
public class AuthUserDetailsServiceImpl implements UserDetailsService {
private static final Logger logger = LoggerFactory.getLogger(AuthUserDetailsServiceImpl.class);
@Autowired
private TUserService userService;
@Autowired
private TRoleService roleService;
/**
* 通过账号查找用户、角色的信息
*
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = 数据库查询用户;
if (user == null) {
//用户名不存在
throw new ServicesException(RespBeanEnum.USER_ACCOUNT_NOT_EXIST);
} else {
List<String> roles = 根据用户id查询出用户权限名字;
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (String role : roles) {
authorities.add(new SimpleGrantedAuthority(role));
}
return new AuthUser(user, authorities);
}
}
}
过滤器
@Component
public class MyOncePerRequestFilter extends OncePerRequestFilter {
@Value("${jwt.tokenHeader}")
private String header;
@Autowired
private RedisCache redisCache;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
// header的值是在yml文件中定义的 “Authorization”
String token = request.getHeader(header);
System.out.println("MyOncePerRequestFilter-token = " + token);
if (!StrUtil.isEmpty(token)) {
String username = null;
try {
Claims claims = JwtUtil.parseJWT(token);
username = claims.getSubject();
} catch (Exception e) {
e.printStackTrace();
// throw new ServicesException("非法Token,请重新登陆", RespBeanEnum.ERROR);
WriteJSON(request,response,new RespBean(RespBeanEnum.ERROR,"非法Token,请重新登陆"));
return;
}
String redisToken = redisCache.getCacheObject("Token_" + username);
System.out.println("MyOncePerRequestFilter-redisToken = " + redisToken);
if (StrUtil.isEmpty(redisToken)) {
//token令牌验证失败
// throw new ServicesException(RespBeanEnum.TOKEN_VALIDATE_FAILED);
//输出JSON
WriteJSON(request,response,new RespBean(RespBeanEnum.TOKEN_VALIDATE_FAILED));
return;
}
//对比前端发送请求携带的的token是否与redis中存储的一致
if (!Objects.isNull(redisToken) && redisToken.equals(token)) {
AuthUser authUser = redisCache.getCacheObject("UserDetails_" + username);
System.out.println("MyOncePerRequestFilter-authUser = " + authUser);
if (Objects.isNull(authUser)) {
// throw new ServicesException(RespBeanEnum.USER_NOT_LOGIN);
WriteJSON(request,response,new RespBean(RespBeanEnum.USER_NOT_LOGIN));
return;
}
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(authUser, null, authUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
chain.doFilter(request, response);
}
private void WriteJSON(HttpServletRequest request,
HttpServletResponse response,
Object obj) throws IOException, ServletException {
//这里很重要,否则页面获取不到正常的JSON数据集
response.setContentType("application/json;charset=UTF-8");
//跨域设置
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Method", "POST,GET");
//输出JSON
PrintWriter out = response.getWriter();
out.write(JSON.toJSONString(obj));
out.flush();
out.close();
}
}
//正常放行
//UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(authUser, null, authUser.getAuthorities());
// SecurityContextHolder.getContext().setAuthentication(authenticationToken);
//chain.doFilter(request, response);
//没有token
//return;就行
配置类
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyOncePerRequestFilter myOncePerRequestFilter;
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//1、关闭csrf,关闭Session
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//2、设置不需要认证的URL
http
.authorizeRequests()
//允许未登录的用户进行访问
.antMatchers("/doLogin").anonymous()
//其余url都要认证才能访问
.anyRequest().authenticated();
//3、在UsernamePasswordAuthenticationFilter前添加认证过滤器
http.addFilterBefore(myOncePerRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}