WebSecurityConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsServiceImpl userDetailsService;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
public WebSecurityConfig(UserDetailsServiceImpl userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) {
this.userDetailsService = userDetailsService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
@Bean
public JWTAuthenticationAgentFilter JWTAuthenticationAgentFilterBean() throws Exception {
return new JWTAuthenticationAgentFilter(authenticationManager());
}
@Bean
public JWTAuthenticationCustomerFilter JWTAuthenticationCustomerFilterBean() throws Exception {
return new JWTAuthenticationCustomerFilter(authenticationManager());
}
@Bean
public JWTAuthenticationManagerFilter JWTAuthenticationManagerFilterBean() throws Exception {
return new JWTAuthenticationManagerFilter(authenticationManager());
}
@Bean
public JWTAuthorizationFilter JWTAuthorizationFilterBean() throws Exception {
return new JWTAuthorizationFilter(authenticationManager());
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
// 由于使用的是JWT,我们这里不需要csrf
.csrf().disable()
.exceptionHandling()
//access fail
//.authenticationEntryPoint(authEntryPoint)
//role fail
//.accessDeniedHandler(authAccessDenied)
.and()
// 基于token,所以不需要session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.headers().frameOptions().sameOrigin()
.and()
.authorizeRequests()
// 允许对于网站静态资源的无授权访问
.antMatchers("/favicon.ico").permitAll()
.antMatchers("/swagger-ui.html", "/webjars/springfox-swagger-ui/**", "/swagger-resources/**", "/v2/api-docs").permitAll()
.antMatchers(HttpMethod.POST, "/user/user_agent", "/user/user_agent/password_reset").permitAll()
.antMatchers(HttpMethod.GET, "/user/user_agent/info_of_register", "/user/user_agent/phone_exist").permitAll()
.antMatchers(HttpMethod.POST, "/user/user_customer", "/user/user_customer/password_reset").permitAll()
.antMatchers(HttpMethod.GET, "/user/user_customer/phone_exist").permitAll()
.antMatchers(HttpMethod.POST, "/user/user_manager").permitAll()
.antMatchers(HttpMethod.POST, "/file/upload").permitAll()
.antMatchers(HttpMethod.GET, "/product/group", "/product/product_base", "/product/product_base/one_001/**", "/product/product_info", "/product/product_specific/type_list/**").permitAll()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated().and()
// login filter
.addFilterBefore(JWTAuthenticationAgentFilterBean(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(JWTAuthenticationCustomerFilterBean(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(JWTAuthenticationManagerFilterBean(), UsernamePasswordAuthenticationFilter.class)
.addFilter(JWTAuthorizationFilterBean())
// auth filter
// 禁用缓存
.headers().cacheControl();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// Create a default account
auth.userDetailsService(this.userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
}
AuthLoginFilter.java
import com.google.common.base.Strings;
import com.jianjian.shop.common.constant.BusinessType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class JWTAuthenticationManagerFilter extends AbstractAuthenticationProcessingFilter {
private static String tokenHeader;
private static String tokenPrefix;
@Value("${jwt.header}")
public void setTokenHeader(String value) {
tokenHeader = value;
}
@Value("${jwt.tokenPrefix}")
public void setTokenPrefix(String value) {
tokenPrefix = value;
}
public JWTAuthenticationManagerFilter(AuthenticationManager authenticationManager) {
super(new AntPathRequestMatcher("/login_manager", "POST"));
setAuthenticationManager(authenticationManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException {
return this.getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(obtainUsername(req) + "__" + BusinessType.UserType.user_manager.name() + "__", obtainPassword(req)));
}
@Override
protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain, Authentication auth) throws IOException {
res.setHeader("content-type", "application/json;charset=UTF-8");
String token = JWTTokenUtil.tokenGenerate((UserDetailsImpl) auth.getPrincipal());
if (!Strings.isNullOrEmpty(token)) {
res.addHeader(tokenHeader, tokenPrefix + token);
}
res.getWriter().print("{\"result_code\":\"0\"}");
}
private static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
private static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
private String obtainPassword(HttpServletRequest request) {
return request.getParameter(SPRING_SECURITY_FORM_PASSWORD_KEY);
}
private String obtainUsername(HttpServletRequest request) {
return request.getParameter(SPRING_SECURITY_FORM_USERNAME_KEY);
}
}
AuthFilter.java
import com.google.common.base.Strings;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.Date;
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
private static String tokenHeader;
private static String tokenPrefix;
@Value("${jwt.header}")
public void setTokenHeader(String value) {
tokenHeader = value;
}
@Value("${jwt.tokenPrefix}")
public void setTokenPrefix(String value) {
tokenPrefix = value;
}
public JWTAuthorizationFilter(AuthenticationManager authManager) {
super(authManager);
}
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
String header = req.getHeader(tokenHeader);
if (header == null || !header.startsWith(tokenPrefix)) {
chain.doFilter(req, res);
logger.info("无认证");
return;
}
String token = header.replace(tokenPrefix, "");
try {
Claims claims = JWTTokenUtil.tokenParse(token);
if (claims != null && claims.containsKey("userUuid") && !Strings.isNullOrEmpty(claims.get("userUuid").toString())) {
if (claims.getExpiration().after(new Date())) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(claims, null, Collections.emptyList());
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
logger.warn("失效");
}
}
} catch (IllegalArgumentException e) {
logger.error("an error occured during getting username from token", e);
} catch (SignatureException | MalformedJwtException e) {
logger.error("Authentication Failed. Username or Password not valid.");
} catch (ExpiredJwtException e) {
logger.warn("the token is expired and not valid anymore", e);
}
chain.doFilter(req, res);
}
}
AuthEntryPoint.java
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class AuthEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
System.out.println(authException.getMessage());
//Full authentication is required to access this resource
response.setHeader("content-type", "application/json;charset=UTF-8");
String error = response.getHeader("authError");
if (error != null && !StringUtils.isEmpty(error))
response.getWriter().print(error);
}
}
AuthAccessDenied.java
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class AuthAccessDenied implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
System.out.println(accessDeniedException.getMessage());
}
}
AuthUserDetailsService.java
import com.jianjian.shop.common.constant.BusinessType;
import com.jianjian.shop.domain.usercenter.po.UserAgent;
import com.jianjian.shop.domain.usercenter.po.UserCustomer;
import com.jianjian.shop.domain.usercenter.po.UserManager;
import com.jianjian.shop.domain.usercenter.vo.UserBaseVO_001;
import com.jianjian.shop.security.repository.UserAgentRepository;
import com.jianjian.shop.security.repository.UserCustomerRepository;
import com.jianjian.shop.security.repository.UserManagerRepository;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.Optional;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserAgentRepository userAgentRepository;
private final UserCustomerRepository userCustomerRepository;
private final UserManagerRepository userManagerRepository;
public UserDetailsServiceImpl(UserAgentRepository userAgentRepository, UserCustomerRepository userCustomerRepository, UserManagerRepository userManagerRepository) {
this.userAgentRepository = userAgentRepository;
this.userCustomerRepository = userCustomerRepository;
this.userManagerRepository = userManagerRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserBaseVO_001 userBaseVO_001;
if (username.endsWith("__" + BusinessType.UserType.user_agent.name() + "__")) {
Optional userAgentOptional = this.userAgentRepository.findByFPhone(username.replace("__" + BusinessType.UserType.user_agent.name() + "__", ""));
if (!userAgentOptional.isPresent()) {
throw new UsernameNotFoundException("用户不存在");
}
UserAgent userAgent = userAgentOptional.get();
userBaseVO_001 = UserBaseVO_001.builder()
.userName(userAgent.getFPhone())
.password(userAgent.getUserBase().getFPassword())
.userType(userAgent.getUserBase().getFUserType())
.uuid(userAgent.getId())
.build();
} else if (username.endsWith("__" + BusinessType.UserType.user_customer.name() + "__")) {
Optional userCustomerOptional = this.userCustomerRepository.findByFPhone(username.replace("__" + BusinessType.UserType.user_customer.name() + "__", ""));
if (!userCustomerOptional.isPresent()) {
throw new UsernameNotFoundException("用户不存在");
}
UserCustomer userCustomer = userCustomerOptional.get();
userBaseVO_001 = UserBaseVO_001.builder()
.userName(userCustomer.getFPhone())
.password(userCustomer.getUserBase().getFPassword())
.userType(userCustomer.getUserBase().getFUserType())
.uuid(userCustomer.getId())
.build();
} else if (username.endsWith("__" + BusinessType.UserType.user_manager.name() + "__")) {
Optional userManagerOptional = this.userManagerRepository.findByFPhone(username.replace("__" + BusinessType.UserType.user_manager.name() + "__", ""));
if (!userManagerOptional.isPresent()) {
throw new UsernameNotFoundException("用户不存在");
}
UserManager userManager = userManagerOptional.get();
userBaseVO_001 = UserBaseVO_001.builder()
.userName(userManager.getFPhone())
.password(userManager.getUserBase().getFPassword())
.userType(userManager.getUserBase().getFUserType())
.uuid(userManager.getId())
.build();
} else {
throw new UsernameNotFoundException("用户不存在");
}
return new UserDetailsImpl(userBaseVO_001.getUserName(), userBaseVO_001.getPassword(), Collections.emptyList(), userBaseVO_001.getUuid(), userBaseVO_001.getUserType());
}
}
AuthUser.java
import lombok.Getter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import java.util.Collection;
@Getter
class UserDetailsImpl extends User {
private final String userUuid;
private final String userType;
UserDetailsImpl(String username, String password, Collection extends GrantedAuthority> authorities, String userUuid, String userType) {
super(username, password, authorities);
this.userUuid = userUuid;
this.userType = userType;
}
}
JWTTokenUtil.java
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
@Component
public class JWTTokenUtil {
private static long expirationTime;
private static String secret;
@Value("${jwt.expirationTime}")
public void setExpirationTime(long value) {
expirationTime = value;
}
@Value("${jwt.secret}")
public void setSecret(String value) {
secret = value;
}
public static String tokenGenerate(UserDetailsImpl userDetails) {
return Jwts.builder()
.setClaims(new HashMap() {{
put("userUuid", userDetails.getUserUuid());
put("userType", userDetails.getUserType());
}})
.setSubject(userDetails.getUserUuid())
.setIssuer("jianjian")
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + expirationTime))
.signWith(SignatureAlgorithm.HS256, secret)
.compact();
}
public static Claims tokenParse(String token) {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}
/*private R getClaimFromToken(String token, Function claimsResolver) {
final Claims claims = tokenParse(token);
return claimsResolver.apply(claims);
}*/
}