SpringBoot整合SpringSecurity和JWT实现mymes认证和授权(二)
接上一篇接上一篇,SpringSecurity的配置类相关依赖以及方法说明
configure(HttpSecurity httpSecurity):用于拦截url路径、JWT过滤和异常处理 configure(AuthenticationManagerBuilder auth):用于配置userDetailsService和PasswordEncoder JwtAuthenticationTokenFilter:在用户名和密码前添加过滤器,若有token,会根据token自行登录 RestfulAccessDeniedHandler:在用户没有访问权限的时候,返回JSON格式的处理结果 RestAuthenticationEntryPoint:在token失效或者没有登录情况下,返回JSON格式处理结果 PasswordEncoder:SpringSecurity定义的用于对密码进行编码及比对的接口,目前使用的是BCryptPasswordEncoder; IgnoreUrlsConfig:用于从application.yml中获取不需要安全保护的资源路径 UserDetailsService:SpringSecurity核心接口,获取用户信息
添加IgnoreUrlsConfig
package com.cn.mymes.utils.config;/* *Created by zbb on 2021/1/6 **/ import lombok.Getter; import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; import java.util.ArrayList; import java.util.List; /** * 用于配置不需要保护的资源路径 * */ @Getter @Setter @ConfigurationProperties(prefix = "secure.ignored") public class IgnoreUrlsConfig { private List<String> urls = new ArrayList<>(); }
在application.yml中配置下不需要安全保护的资源路径
secure: ignored: urls: #安全路径白名单 - /swagger-ui.html - /swagger-resources/** - /swagger/** - /**/v2/api-docs - /**/*.js - /**/*.css - /**/*.png - /**/*.ico - /webjars/springfox-swagger-ui/** - /actuator/** - /druid/** - /admin/login - /admin/register - /admin/info - /admin/logout
添加Token过滤器JwtAuthenticationTokenFilter
package com.cn.mymes.component; import com.cn.mymes.utils.JwtTokenUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; 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; /** *token登录过滤器 * */ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationTokenFilter.class); @Autowired private UserDetailsService userDetailsService; @Autowired private JwtTokenUtil jwtTokenUtil; @Value("${jwt.tokenHeader}") private String tokenHeader; @Value("${jwt.tokenHead}") private String tokenHead; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String authHeader = request.getHeader(this.tokenHeader); if (authHeader != null && authHeader.startsWith(this.tokenHead)) { String authToken = authHeader.substring(this.tokenHead.length());// The part after "Bearer " String username = jwtTokenUtil.getUserNameFromToken(authToken); LOGGER.info("checking username:{}", username); if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); if (jwtTokenUtil.validateToken(authToken, userDetails)) { UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); LOGGER.info("authenticated user:{}", username); SecurityContextHolder.getContext().setAuthentication(authentication); } } } chain.doFilter(request, response); } }
添加无权访问时RestfulAccessDeniedHandler方法
package com.cn.mymes.component; import cn.hutool.json.JSONUtil; import com.cn.mymes.common.CommonResult; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.web.access.AccessDeniedHandler; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** *在没有权限访问时,返回自定义JSON格式结果 */ public class RestfulAccessDeniedHandler implements AccessDeniedHandler{ @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException { response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Cache-Control","no-cache"); response.setCharacterEncoding("UTF-8"); response.setContentType("application/json"); response.getWriter().println(JSONUtil.parse(CommonResult.forbidden(e.getMessage()))); response.getWriter().flush(); } }
添加未登录或者登录过期返回自定义结果的RestAuthenticationEntryPoint方法
package com.cn.mymes.component; import cn.hutool.json.JSONUtil; import com.cn.mymes.common.CommonResult; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * 未登录或者登录过期时,返回自定义JSON格式 */ public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Cache-Control","no-cache"); response.setCharacterEncoding("UTF-8"); response.setContentType("application/json"); response.getWriter().println(JSONUtil.parse(CommonResult.unauthorized(authException.getMessage()))); response.getWriter().flush(); } }
添加SpringSecurity核心接口,获取用户信息
package com.cn.mymes.domain; import com.cn.mymes.mgb.model.UmsAdmin; import com.cn.mymes.mgb.model.UmsResource; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; /** * SpringSecurity核心,获取用户信息 * */ public class AdminUserDetails implements UserDetails { private UmsAdmin umsAdmin; private List<UmsResource> resourceList; public AdminUserDetails(UmsAdmin umsAdmin, List<UmsResource> resourceList) { this.umsAdmin = umsAdmin; this.resourceList = resourceList; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { //返回当前用户的角色 return resourceList.stream() .map(role ->new SimpleGrantedAuthority(role.getId()+":"+role.getName())) .collect(Collectors.toList()); } @Override public String getPassword() { return umsAdmin.getPassword(); } @Override public String getUsername() { return umsAdmin.getUsername(); } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return umsAdmin.getStatus().equals(1); } }
明天讲MyMes中SpringSecurity项目权限管理中动态管理部分的实现
公众号https://mp.weixin.qq.com/s/nfat2WWWUXdmfUGFBAVEuA