package me.zhengjie.core.security; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Getter; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.co
package me.zhengjie.core.security; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Getter; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import java.sql.Timestamp; import java.util.*; /** * @author jie * @date 2018-11-23 */ @Getter @AllArgsConstructor public class JwtUser implements UserDetails { @JsonIgnore private final Long id; private final String username; @JsonIgnore private final String password; private final String avatar; private final String email; @JsonIgnore private final Collection<? extends GrantedAuthority> authorities; private final boolean enabled; private Timestamp createTime; @JsonIgnore private final Date lastPasswordResetDate; @JsonIgnore @Override public boolean isAccountNonExpired() { return true; } @JsonIgnore @Override public boolean isAccountNonLocked() { return true; } @JsonIgnore @Override public boolean isCredentialsNonExpired() { return true; } @JsonIgnore @Override public String getPassword() { return password; } @Override public boolean isEnabled() { return enabled; } /** * 在我们保存权限的时候加上了前缀ROLE_,因此在这里需要处理下数据 * @return */ public Collection getRoles() { Set<String> roles = new LinkedHashSet<>(); for (GrantedAuthority authority : authorities) { roles.add(authority.getAuthority().substring(5)); } return roles; } }
package me.zhengjie.core.security; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.Serializable; @Component public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable { private static final long serialVersionUID = -8970718410437077606L; @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { /** * 当用户尝试访问安全的REST资源而不提供任何凭据时,将调用此方法发送401 响应 */ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException==null?"Unauthorized":authException.getMessage()); } }
package me.zhengjie.core.security; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.Serializable; @Component public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable { private static final long serialVersionUID = -8970718410437077606L; @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { /** * 当用户尝试访问安全的REST资源而不提供任何凭据时,将调用此方法发送401 响应 */ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException==null?"Unauthorized":authException.getMessage()); } }
package me.zhengjie.core.security; import io.jsonwebtoken.ExpiredJwtException; import me.zhengjie.core.utils.JwtTokenUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; 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.stereotype.Component; 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; @Component public class JwtAuthorizationTokenFilter extends OncePerRequestFilter { private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final UserDetailsService userDetailsService; private final JwtTokenUtil jwtTokenUtil; private final String tokenHeader; public JwtAuthorizationTokenFilter(@Qualifier("jwtUserDetailsService") UserDetailsService userDetailsService, JwtTokenUtil jwtTokenUtil, @Value("${jwt.header}") String tokenHeader) { this.userDetailsService = userDetailsService; this.jwtTokenUtil = jwtTokenUtil; this.tokenHeader = tokenHeader; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { logger.debug("processing authentication for ‘{}‘", request.getRequestURL()); final String requestHeader = request.getHeader(this.tokenHeader); String username = null; String authToken = null; if (requestHeader != null && requestHeader.startsWith("Bearer ")) { authToken = requestHeader.substring(7); try { username = jwtTokenUtil.getUsernameFromToken(authToken); } catch (ExpiredJwtException e) { logger.error(e.getMessage()); } } logger.debug("checking authentication for user ‘{}‘", username); if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { logger.debug("security context was null, so authorizating user"); // It is not compelling necessary to load the use details from the database. You could also store the information // in the token and read it from it. It‘s up to you ;) UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); // For simple validation it is completely sufficient to just check the token integrity. You don‘t have to call // the database compellingly. Again it‘s up to you ;) if (jwtTokenUtil.validateToken(authToken, userDetails)) { UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); logger.info("authorizated user ‘{}‘, setting security context", username); SecurityContextHolder.getContext().setAuthentication(authentication); } } chain.doFilter(request, response); } }
package me.zhengjie.core.service; import me.zhengjie.common.exception.EntityNotFoundException; import me.zhengjie.common.utils.ValidationUtil; import me.zhengjie.core.security.JwtUser; import me.zhengjie.system.domain.Permission; import me.zhengjie.system.domain.Role; import me.zhengjie.system.domain.User; import me.zhengjie.system.repository.PermissionRepository; import me.zhengjie.system.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.Cacheable; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; /** * @author jie * @date 2018-11-22 */ @Service @Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) public class JwtUserDetailsService implements UserDetailsService { @Autowired private UserRepository userRepository; @Autowired private PermissionRepository permissionRepository; @Override public UserDetails loadUserByUsername(String username){ User user = null; if(ValidationUtil.isEmail(username)){ user = userRepository.findByEmail(username); } else { user = userRepository.findByUsername(username); } if (user == null) { throw new EntityNotFoundException(User.class, "name", username); } else { return create(user); } } public UserDetails create(User user) { return new JwtUser( user.getId(), user.getUsername(), user.getPassword(), user.getAvatar(), user.getEmail(), mapToGrantedAuthorities(user.getRoles(),permissionRepository), user.getEnabled(), user.getCreateTime(), user.getLastPasswordResetTime() ); } private static List<GrantedAuthority> mapToGrantedAuthorities(Set<Role> roles,PermissionRepository permissionRepository) { Set<Permission> permissions = new HashSet<>(); for (Role role : roles) { Set<Role> roleSet = new HashSet<>(); roleSet.add(role); permissions.addAll(permissionRepository.findByRoles(roleSet)); } return permissions.stream() .map(permission -> new SimpleGrantedAuthority("ROLE_"+permission.getName())) .collect(Collectors.toList()); } }
package me.zhengjie.core.service; import me.zhengjie.common.exception.EntityNotFoundException; import me.zhengjie.common.utils.ValidationUtil; import me.zhengjie.core.security.JwtUser; import me.zhengjie.system.domain.Permission; import me.zhengjie.system.domain.Role; import me.zhengjie.system.domain.User; import me.zhengjie.system.repository.PermissionRepository; import me.zhengjie.system.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.Cacheable; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; /** * @author jie * @date 2018-11-22 */ @Service @Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) public class JwtUserDetailsService implements UserDetailsService { @Autowired private UserRepository userRepository; @Autowired private PermissionRepository permissionRepository; @Override public UserDetails loadUserByUsername(String username){ User user = null; if(ValidationUtil.isEmail(username)){ user = userRepository.findByEmail(username); } else { user = userRepository.findByUsername(username); } if (user == null) { throw new EntityNotFoundException(User.class, "name", username); } else { return create(user); } } public UserDetails create(User user) { return new JwtUser( user.getId(), user.getUsername(), user.getPassword(), user.getAvatar(), user.getEmail(), mapToGrantedAuthorities(user.getRoles(),permissionRepository), user.getEnabled(), user.getCreateTime(), user.getLastPasswordResetTime() ); } private static List<GrantedAuthority> mapToGrantedAuthorities(Set<Role> roles,PermissionRepository permissionRepository) { Set<Permission> permissions = new HashSet<>(); for (Role role : roles) { Set<Role> roleSet = new HashSet<>(); roleSet.add(role); permissions.addAll(permissionRepository.findByRoles(roleSet)); } return permissions.stream() .map(permission -> new SimpleGrantedAuthority("ROLE_"+permission.getName())) .collect(Collectors.toList()); } }