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);@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate JwtTokenUtil jwtTokenUtil;@Value(\"${jwt.tokenHeader}\")private String tokenHeader;@Value(\"${jwt.tokenHead}\")private String tokenHead;@Overrideprotected 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{@Overridepublic 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 {@Overridepublic 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;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {//返回当前用户的角色return resourceList.stream().map(role ->new SimpleGrantedAuthority(role.getId()+\":\"+role.getName())).collect(Collectors.toList());}@Overridepublic String getPassword() {return umsAdmin.getPassword();}@Overridepublic String getUsername() {return umsAdmin.getUsername();}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return umsAdmin.getStatus().equals(1);}}
明天讲MyMes中SpringSecurity项目权限管理中动态管理部分的实现