当前位置 : 主页 > 编程语言 > java >

【精品】SpringSecurity在前后端分离项目中的应用

来源:互联网 收集:自由互联 发布时间:2022-10-15
原理 由默认用户登录得到SpringSecurity下用户登录的请求流程: 入门示例:使用SpringSecurity提供的登录页面,实现真正的登录功能 第一步:自定义UserDetailsService @Servicepublic class WegoUserDe

原理

在这里插入图片描述

由默认用户登录得到SpringSecurity下用户登录的请求流程:

入门示例:使用SpringSecurity提供的登录页面,实现真正的登录功能

第一步:自定义UserDetailsService

@Service public class WegoUserDetailsService implements UserDetailsService { @Resource private MemberMapper memberMapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //认证:根据用户名去查询对应的用户信息 LambdaQueryWrapper<Member> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(Member::getUsername,username); Member member = memberMapper.selectOne(queryWrapper); //如果没有查询到用户抛出异常 if(member == null){ throw GlobalException.builder().code(401).msg("用户名或密码不正确").build(); } // TODO: 授权:查询用户的权限信息 // 将用户信息+权限信息封装成UserDetails对象 LoginMemberDetails loginMemberDetails = new LoginMemberDetails(); loginMemberDetails.setMember(member); return loginMemberDetails; } }

第二步:自定义UserDetails:

public class LoginMemberDetails implements UserDetails { @Setter private Member member; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return null; } /** * 登录密码 * @return */ @Override public String getPassword() { return member.getPassword(); } /** * 登录账户 * @return */ @Override public String getUsername() { return member.getUsername(); } /** * 返回对象是否未过期 * @return */ @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }

第三步:测试

为了测试,修改待登录用户的密码为:{noop}明文密码,比如: 在这里插入图片描述

密码加密存储

默认使用的PasswordEncoder要求数据库中的密码格式为:{id}password。它会根据id去判断密码的加密方式,但是我们一般不会采用这种方式,所以就需要替换PasswordEncoder。 实际项目中推荐使用BCryptPasswordEncoder。只需要把BCryptPasswordEncoder对象注入到Spring容器中,SpringSecurity就会使用该PasswordEncoder进行密码加密。 创建SpringSecurity配置文件,在其中指定加密方式:

@Configuration public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { /** * 密码加密器 * @return */ @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }

将数据库中的密码改成加密后的内容,然后测试就可以了。

用户登录:不再使用默认的用户user+随机字符串登录,使用我们自己数据库中的用户名+密码登录。

SpringSecurity需要对自定义的登录接口放行,让用户可以直接访问到这个接口。 在登录接口中需要通过AuthenticationManager的authenticate()方法进行用户认证,故需要先在SpringSecurity配置文件中把AuthenticationManager注入容器。 认证成功后生成一个jwt,在登录成功后的响应中返回。 为了让用户下回请求时能够通过jwt快速识别出用户,我们将用户信息缓存到Redis中,将用户的id作为key。

第一步:自定义UserDetails类:

@Getter @Setter @ToString public class WegoUserDetails implements UserDetails { private User user; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return null; } @Override public String getPassword() { if(user == null){ return null; } return user.getPassword(); } @Override public String getUsername() { if(user == null){ return null; } 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; } }

第二步:自定义UserDatailsService

在其中实现根据用户名查找用户,并将用户的信息封装成我们自己的UserDatails对象并返回

@Service public class WegoUserDetailsService implements UserDetailsService { @Resource private UserService userService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userService.getOne(Wrappers.<User>query().eq("username", username)); //TODO:查询权限信息 WegoUserDetails userDetails = new WegoUserDetails(); userDetails.setUser(user); return userDetails; } }

第三步:修改SpringSecurity配置类

在系统注入AuthenticationManager对象并放行登录接口user/login:

@Configuration public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { /** * 认证用:最终调用DetailsService的具体的登录逻辑 * @return * @throws Exception */ @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(HttpSecurity http) throws Exception { http //关闭csrf .csrf().disable() //禁用Session:不通过Sessin获取SecurityContext .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() //登录接口:匿名访问(未登录可以访问,登录的话不就能访问了) .antMatchers("/user/login").anonymous() //放行 //其他的任何请求都需要鉴权认证 .anyRequest().authenticated() ; } }

第四步:自定义登录接口:

登录接口实现功能: 1、 将用户名+密码封装成UsernamePasswordAuthenticationToken对象 2、 调用AuthenticationManager的authenticate()方法进行登录判断

@RestController @RequestMapping("/user") public class LoginController { @Resource private AuthenticationManager authenticationManager; @PostMapping("/login") public Result login(@RequestBody User user) { UsernamePasswordAuthenticationToken passwordAuthenticationToken = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()); authenticationManager.authenticate(passwordAuthenticationToken); return ResultUtil.success(); } }

第五步:在SpringSecurity配置文件中注入加密类的对象:

/** * 密码加密器 * @return */ @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }

在测试类中,利用该对象生成密码并保存到数据库中

class FafuRbacApplicationTests { @Test public void fun() { PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); System.out.println(passwordEncoder.encode("1234")); } }

第六步:测试

打开postman,在其中请求user/login,注意以post方式+application/json的形式请求。

返回token

第一步:准备JWT工具类:

@Slf4j @Component //@ConfigurationProperties(prefix = "jwt") public class JwtUtil { /** * 携带JWT令牌的HTTP的Header的名称,在实际生产中可读性越差越安全 */ @Getter @Value("${jwt.token}") private String token; /** * 为JWT基础信息加密和解密的密钥 * 在实际生产中通常不直接写在配置文件里面。而是通过应用的启动参数传递,并且需要定期修改。 */ @Value("${jwt.secret}") private String secret; /** * JWT令牌的有效时间,单位秒 * - 默认2周 */ @Value("${jwt.expiration}") private Long expiration; private static String getUUID() { String token = UUID.randomUUID().toString().replaceAll("-", ""); return token; } /** * SecretKey 根据 SECRET 的编码方式解码后得到: * Base64 编码:SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretString)); * Base64URL 编码:SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64URL.decode(secretString)); * 未编码:SecretKey key = Keys.hmacShaKeyFor(secretString.getBytes(StandardCharsets.UTF_8)); */ private static SecretKey getSecretKey(String secret) { byte[] encodeKey = Decoders.BASE64.decode(secret); return Keys.hmacShaKeyFor(encodeKey); } /** * 用claims生成token * * @param claims 数据声明,用来创建payload的私有声明,subject只是claims的一部分 * @return token 令牌 */ private JwtBuilder getJwtBuilder(Map<String, Object> claims) { SecretKey key = getSecretKey(secret); //SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); //两种方式等价 // 添加payload声明 JwtBuilder jwtBuilder = Jwts.builder() // 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的 .setClaims(claims) // 设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。 .setId(getUUID()) // 你也可以改用你喜欢的算法,支持的算法详见:https://github.com/jwtk/jjwt#features // SignatureAlgorithm.HS256:指定签名的时候使用的签名算法,也就是header那部分 .signWith(key, SignatureAlgorithm.HS256) // iat: jwt的签发时间 .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + this.expiration * 1000)); return jwtBuilder; } /** * 生成Token令牌 * * @param username 用户名 * @return 令牌Token */ public String generateToken(String username) { Map<String, Object> claims = new HashMap<>(); claims.put("sub", username); claims.put("created", new Date()); return getJwtBuilder(claims).compact(); } public String generateToken(Serializable id) { Map<String, Object> claims = new HashMap<>(); claims.put("sub", id); claims.put("created", new Date()); return getJwtBuilder(claims).compact(); } /** * 从token中获取数据声明claim * * @param token 令牌token * @return 数据声明claim */ public Claims getClaimsFromToken(String token) { try { SecretKey key = getSecretKey(secret); Claims claims = Jwts.parserBuilder() .setSigningKey(key) .build() .parseClaimsJws(token).getBody(); return claims; } catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | IllegalArgumentException e) { log.error("token解析错误", e); throw new IllegalArgumentException("Token invalided."); } } /** * 从token中获取登录用户名 * * @param token 令牌 * @return 用户名 */ public String getSubjectFromToken(String token) { String subject; try { Claims claims = getClaimsFromToken(token); subject = claims.getSubject(); } catch (Exception e) { subject = null; } return subject; } /** * 获取token的过期时间 * * @param token token * @return 过期时间 */ public Date getExpirationFromToken(String token) { return getClaimsFromToken(token).getExpiration(); } public String getUserRole(String token) { return (String) getClaimsFromToken(token).get("role"); } /** * 判断token是否过期 * * @param token 令牌 * @return 是否过期:已过期返回true,未过期返回false */ public Boolean isTokenExpired(String token) { Date expiration = getExpirationFromToken(token); return expiration.before(new Date()); } /** * 验证令牌:判断token是否非法 * * @param token 令牌 * @param username 用户名 * @return 如果token未过期且合法,返回true,否则返回false */ public Boolean validateToken(String token, String username) { //如果已经过期返回false if (isTokenExpired(token)) { return false; } String usernameFromToken = getSubjectFromToken(token); return username.equals(usernameFromToken); } }

第二步:修改LoginController

在login()方法中,当用户登录成功时,生成token,并放到返回结果中

@RestController @RequestMapping("/user") public class LoginController { @Resource private JwtUtil jwtUtil; @Resource private AuthenticationManager authenticationManager; @PostMapping("/login") public Result login(@RequestBody User user) { UsernamePasswordAuthenticationToken passwordAuthenticationToken = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()); Authentication authenticate = authenticationManager.authenticate(passwordAuthenticationToken); if(authenticate == null){ return ResultUtil.error(401,"error"); } user = ((WegoUserDetails)authenticate.getPrincipal()).getUser(); String token = jwtUtil.generateToken("user:" + user.getId()); return ResultUtil.success().addData("token",token); } }

第三步:修改application.yml,其中添加jwt的配置信息:

jwt: # 为JWT基础信息加密和解密的密钥,长度需要大于等于43 # 在实际生产中通常不直接写在配置文件里面。而是通过应用的启动参数传递,并且需要定期修改 secret: oQZSeguYloAPAmKwvKqqnifiQatxMEPNOvtwPsCLasd # JWT令牌的有效时间,单位秒,默认2周 expiration: 1209600 token: Authorization

第四步:测试:

token认证过滤器

第一步:自定义过滤器

@Component public class JwtAuthenticationFilter extends OncePerRequestFilter { @Resource private ByteRedisUtil<WegoUserDetails> wegoUserDetailsByteRedisUtil; @Resource private JwtUtil jwtUtil; @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { //1、获取用户请求时传递过来的token String token = httpServletRequest.getHeader("Authorization"); if(token == null || token.length() == 0){ //放行到过滤器链中的下一个过滤器过滤 filterChain.doFilter(httpServletRequest,httpServletResponse); return; } //如果用户请求携带有token,解析token Claims claimsFromToken = null; try { claimsFromToken = jwtUtil.getClaimsFromToken(token); } catch (Exception e) { System.out.println("非法的token"); e.printStackTrace(); } //获取用户id String userId = claimsFromToken.getSubject(); //根据用户id,构造出一个Authentication对象,给过滤器链中后面的Filter使用(过滤器链中处理的都是Authentication对象) UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userId,null,null); SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); //放行到过滤器链中的下一个过滤器过滤 filterChain.doFilter(httpServletRequest,httpServletResponse); } }

第二步:在SpringSecurity配置类中配置自定义的过滤器

@Resource private JwtAuthenticationFilter jwtAuthenticationFilter; @Override protected void configure(HttpSecurity http) throws Exception { …… //添加过滤器 http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); }

第三步:测试

1、 先登录,获取token 2、 将token配置到header中,请求任意一个资源

完善token认证过滤器

@Component public class JwtAuthenticationFilter extends OncePerRequestFilter { @Resource private ByteRedisUtil<WegoUserDetails> wegoUserDetailsByteRedisUtil; @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { //…….. //获取用户id String userId = claimsFromToken.getSubject(); //从Redis中获取缓存的用户数据 WegoUserDetails wegoUserDetails = wegoUserDetailsByteRedisUtil.get("user:" + userId); if(wegoUserDetails == null){ System.out.println("无效的token"); } //根据用户id,构造出一个Authentication对象,给过滤器链中后面的Filter使用(过滤器链中处理的都是Authentication对象) UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(wegoUserDetails,null,null); SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); //放行到过滤器链中的下一个过滤器过滤 filterChain.doFilter(httpServletRequest,httpServletResponse); } }

异常处理

原理(套路性内容)

在SpringSecurity中,在认证或者授权的过程中出现的异常会被ExceptionTranslationFilter捕获到,在ExceptionTranslationFilter中会去判断这个异常是认证失败还是授权失败产生的:
  • 认证过程中出现的异常,会被封装成AuthenticationException,SpringSecurity会调用AuthenticationEntryPoint对象的方法处理这个异常
  • 授权过程中出现的异常,会被封装成AccessDeniedException,SpringSecurity会调用AccessDeniedHandler对象的方法处理这个异常 所以,自定义异常处理,只需要自定义AuthenticationEntryPoint和AccessDeniedHanler,然后在SpringSecurity中进行配置即可。

Spring Security 中的异常主要分为两大类:一类是认证异常,另一类是授权相关的异常:

  • AuthenticationException 是在用户认证的时候出现错误时抛出的异常。系统用户不存在、被锁定、凭证失效、密码错误等认证过程中出现的异常都由 AuthenticationException 处理。主要的子类如图: 在这里插入图片描述

  • AccessDeniedException 主要是在用户在访问受保护资源时被拒绝而抛出的异常。主要是 CSRF 相关的异常和授权服务异常。主要的子类如图: 在这里插入图片描述

状态码:

  • 401 未授权状态 HTTP 401 错误 - 未授权(Unauthorized) 一般来说该错误消息表明您首先需要登录(输入有效的用户名和密码)。 如果你刚刚输入这些信息,立刻就看到一个 401 错误,就意味着,无论出于何种原因您的用户名和密码其中之一或两者都无效(输入有误,用户名暂时停用,账户被锁定,凭证失效等) 。总之就是认证失败了。其实正好对应我们上面的 AuthenticationException 。

  • 403 被拒绝状态 HTTP 403 错误 - 被禁止(Forbidden) 出现该错误表明您在访问受限资源时没有得到许可。服务器理解了本次请求但是拒绝执行该任务,该请求不该重发给服务器。并且服务器想让客户端知道为什么没有权限访问特定的资源,服务器应该在返回的信息中描述拒绝的理由。一般实践中我们会比较模糊的表明原因。 该错误对应了我们上面的 AccessDeniedException 。

示例

第一步:自定义认证失败处理器

/** * 认证失败处理器 * * @author hc */ @Component public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { response.setStatus(200); response.setContentType("application/json"); response.setCharacterEncoding("utf-8"); String message = authException.getMessage(); if (message == null){ message = "登录失败"; } String json = "{\"code\":\"401\",\"msg\":"+ message +"}"; response.getWriter().write(json); } }

第二步:自定义授权失败处理器

/** * 授权失败处理器 * * @author hc */ @Component public class AccessDeniedHandlerImpl implements AccessDeniedHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException { response.setStatus(200); response.setContentType("application/json"); response.setCharacterEncoding("utf-8"); String message = accessDeniedException.getMessage(); if (message == null){ message = "您的权限不足"; } String json = "{\"code\":\"403\",\"msg\":"+ message +"}"; response.getWriter().write(json); } }

第三步:在SpringSecurity配置文件中配置:

@Resource private AuthenticationEntryPointImpl authenticationEntryPoint; @Resource private AccessDeniedHandlerImpl accessDeniedHandler; @Override protected void configure(HttpSecurity http) throws Exception { …… //处理异常处理器 http.exceptionHandling() .authenticationEntryPoint(authenticationEntryPoint) //认证失败处理器 .accessDeniedHandler(accessDeniedHandler) //授权失败处理器 ; }

第四步:测试。

1、 将Redis中的用户删除,然后请求某个资源

2、 错误的用户名or密码登录

退出登录

在控制器中提供一个退出登录的接口,然后获取SecurityContextHolder中的认证信息,最后删除Redis中对应的数据即可。

代码实现

@RestController @RequestMapping("/user") public class LogoutController { @Resource private ByteRedisUtil<WegoUserDetails> redisUtil; @GetMapping("/logout") public String logout(){ //获取SecurityContextHolder中的用户id UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); WegoUserDetails userDatails = (WegoUserDetails) authentication.getPrincipal(); Long userId = userDatails.getUser().getId(); //从Redis缓存中删除指定id的用户 redisUtil.del(GlobalConst.REDIS_USER_KEY+userId); return "{\"code\":200,\"msg\":\"注销成功!\"}"; } }

测试

1、 正确用户名和密码登录,发现redis中缓存了数据 2、 访问某个资源,ok 3、 退出登录,发现Redis中缓存的数据没有了 4、 再次访问相同的资源,发现访问不到了:

授权

原理

SpringSecurity使用默认的FilterSecurityInterceptor进行权限校验。FilterSecurityInterceptor会从SecurityContextHolder获取 Authentication,然后获取其中的权限信息,从而知道当前用户是否拥有访问指定资源所需要的权限。 所以我们需要将当前登录用户的权限信息也存入到Authenticaion中。 只需要将用户的“权限+角色”信息存放到Authentication(在过滤器链中处理的对象)中,SpringSecurity就能自动处理权限验证

示例

准备工作

第一步:在RoleMapper.java接口中添加如下根据用户id获取该用户拥有的role的方法:
/** * 查询指定id的用户的role * @param userId * @return 角色名称-角色编码 */ @Select(""" SELECT tb_role.id, tb_role.`code` FROM tb_role INNER JOIN tb_user_role ON tb_role.id = tb_user_role.role_id WHERE tb_user_role.user_id = #{userId} """) List<Role> selectRoleCodeByUserId(@Param("userId") Long userId);
第二步:在PermissionMapper.java接口中添加如下根据Role的id获取该Role拥有的Permission的信息:
@Select(""" SELECT tb_permission.`code` FROM tb_role_permission INNER JOIN tb_permission ON tb_role_permission.permission_id = tb_permission.id WHERE tb_role_permission.role_id = #{roleId,jdbcType=BIGINT} """) List<String> selectPermissionCodeByRoleId(@Param("roleId") Long roleId);
第三步:在UserServiceImpl类中添加如下根据用户id获取该用户拥有的角色与权限的方法:
@Resource private RoleMapper roleMapper; @Resource private PermissionMapper permissionMapper; @Override public Set<String> getRolePermissionCodeByUserId(Long userId){ Set<String> rolePermissionSet = new HashSet<>(); ////根据用户id查询角色code List<Role> roleList = roleMapper.selectRoleCodeByUserId(userId); for (Role role : roleList) { rolePermissionSet.add("ROLE_"+role.getCode()); // 根据角色id查询权限code List<String> permissionList = permissionMapper.selectPermissionCodeByRoleId(role.getId()); for (String permission : permissionList) { rolePermissionSet.add(permission); } } return rolePermissionSet; }

具体实现

第一步:修改UserDetails类,在其中添加如下代码:
//用户角色+权限 private Set<String> list; public WegoUserDetails(User user, Set<String> list) { this.user = user; this.list = list; } private List<SimpleGrantedAuthority> authorities; @Override public Collection<? extends GrantedAuthority> getAuthorities() { if(authorities == null) { authorities = list.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()); } return authorities; }
第二步:修改UserDetailsService类,在其中添加获取用户权限的信息:
@Service public class WegoUserDetailsService implements UserDetailsService { @Resource private UserService userService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //认证:根据用户名去查询对应的用户信息 //Wrappers.<User>lambdaQuery().eq(User::getUsername,username); LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(User::getUsername, username); User user = userService.getOne(queryWrapper); //如果没有查询到用户抛出异常 if (user == null) { throw GlobalException.builder().code(401).msg("用户名或密码不正确").build(); } //TODO: 授权:查询用户的权限信息 //List<String> set = List.of("add", "get"); Set<String> set = userService.getRolePermissionCodeByUserId(user.getId()); // 将用户信息+权限信息封装成UserDetails对象 WegoUserDetails wegoUserDetails = new WegoUserDetails(user, set); return wegoUserDetails; } }
第三步:修改JwtAuthenticationFilter,在其中添加获取用户角色+权限的功能:
//TODO: 权限信息 Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities(); //此处必须使用三个参数的构造方法,其中第三个参数是权限信息 UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, authorities);
第四步:测试
  • 第一步:开启相关配置:
@EnableGlobalMethodSecurity(prePostEnabled = true)
  • 第二步:在方法上添加注解
@RestController public class TestController { @PreAuthorize("hasAuthority('sys:user:view')") @GetMapping("/fun1") public Result get() { return ResultUtil.success("sys:user:view"); } @PreAuthorize("hasAuthority('sys:user:list')") @GetMapping("/fun2") public Result add() { return ResultUtil.success("sys:user:list"); } @PreAuthorize("hasRole('admin')") @GetMapping("/fun3") public Result del() { return ResultUtil.success("admin"); } }

设置SpringSecurity跨域

第一步:设置SpringBoot允许跨域

@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry //设置允许跨域的路径 .addMapping("/**") //设置允许路霸请求的域名 .allowedOriginPatterns("*") //是否允许cookie .allowCredentials(true) //设置允许的请求方式 .allowedMethods("GET", "POST", "DELETE", "PUT") //设置允许的header属性 .allowedHeaders("*") //跨域允许时间 .maxAge(3600); } }

第二步:在SpringSecurity配置类的configre()方法中添加如下代码:

//允许跨域 http.cors(); 【文章原创作者:华为云代理 http://www.558idc.com/hw.html处的文章,转载请说明出处】
网友评论