SpringBoot intègre Spring Security et JWT pour obtenir l'authentification et l'autorisation mymes (2)
Suite de l'article précédent, les dépendances liées à la classe de configuration de SpringSecurity et la description de la méthode
- configure (HttpSecurity httpSecurity): utilisé pour intercepter le chemin de l'url, le filtrage JWT et la gestion des exceptions
- configure (AuthenticationManagerBuilder auth): utilisé pour configurer userDetailsService et PasswordEncoder
- JwtAuthenticationTokenFilter: Ajoutez un filtre avant le nom d'utilisateur et le mot de passe. S'il y a un token, il se connectera en fonction du token.
- RestfulAccessDeniedHandler: lorsque l'utilisateur n'a pas de droits d'accès, retourne le résultat du traitement au format JSON
- RestAuthenticationEntryPoint: en cas d'échec du jeton ou d'absence de connexion, retournez le résultat du traitement au format JSON
- PasswordEncoder: l'interface définie par SpringSecurity pour coder et comparer les mots de passe. Actuellement, BCryptPasswordEncoder est utilisé;
- IgnoreUrlsConfig: utilisé pour obtenir des chemins de ressources qui ne nécessitent pas de protection de sécurité depuis application.yml
- UserDetailsService: interface principale de SpringSecurity pour obtenir des informations utilisateur
Ajouter 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<>();
}
Configurer les chemins de ressources qui ne nécessitent pas de protection de sécurité dans 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
Ajouter un filtre de jeton 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);
}
}
Ajouter la méthode RestfulAccessDeniedHandler lorsqu'il n'y a pas d'accès
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();
}
}
Ajoutez la méthode RestAuthenticationEntryPoint qui renvoie un résultat personnalisé qui n'est pas connecté ou a expiré
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();
}
}
Ajouter l'interface principale de SpringSecurity pour obtenir des informations utilisateur
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);
}
}
Demain, je parlerai de l'implémentation de la partie gestion dynamique de la gestion de l'autorité de projet Spring Security dans MyMes