diff --git a/mall-admin/pom.xml b/mall-admin/pom.xml
index ca175d2..d66d5ae 100644
--- a/mall-admin/pom.xml
+++ b/mall-admin/pom.xml
@@ -28,6 +28,10 @@
com.macro.mall
mall-mbg
+
+ com.macro.mall
+ mall-security
+
org.springframework.boot
spring-boot-starter-security
diff --git a/mall-admin/src/main/java/com/macro/mall/component/JwtAuthenticationTokenFilter.java b/mall-admin/src/main/java/com/macro/mall/component/JwtAuthenticationTokenFilter.java
deleted file mode 100644
index fe13f52..0000000
--- a/mall-admin/src/main/java/com/macro/mall/component/JwtAuthenticationTokenFilter.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.macro.mall.component;
-
-import com.macro.mall.util.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.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;
-
-/**
- * JWT登录授权过滤器
- * Created by macro on 2018/4/26.
- */
-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);
- }
-}
diff --git a/mall-admin/src/main/java/com/macro/mall/component/RestAuthenticationEntryPoint.java b/mall-admin/src/main/java/com/macro/mall/component/RestAuthenticationEntryPoint.java
deleted file mode 100644
index 6a107ed..0000000
--- a/mall-admin/src/main/java/com/macro/mall/component/RestAuthenticationEntryPoint.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.macro.mall.component;
-
-import cn.hutool.json.JSONUtil;
-import com.macro.mall.common.api.CommonResult;
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.web.AuthenticationEntryPoint;
-import org.springframework.stereotype.Component;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
-/**
- * 当未登录或者token失效访问接口时,自定义的返回结果
- * Created by macro on 2018/5/14.
- */
-@Component
-public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
- @Override
- public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
- response.setCharacterEncoding("UTF-8");
- response.setContentType("application/json");
- response.getWriter().println(JSONUtil.parse(CommonResult.unauthorized(authException.getMessage())));
- response.getWriter().flush();
- }
-}
diff --git a/mall-admin/src/main/java/com/macro/mall/component/RestfulAccessDeniedHandler.java b/mall-admin/src/main/java/com/macro/mall/component/RestfulAccessDeniedHandler.java
deleted file mode 100644
index 8b22012..0000000
--- a/mall-admin/src/main/java/com/macro/mall/component/RestfulAccessDeniedHandler.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.macro.mall.component;
-
-import cn.hutool.json.JSONUtil;
-import com.macro.mall.common.api.CommonResult;
-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;
-
-/**
- * 当访问接口没有权限时,自定义的返回结果
- * Created by macro on 2018/4/26.
- */
-@Component
-public class RestfulAccessDeniedHandler implements AccessDeniedHandler{
- @Override
- public void handle(HttpServletRequest request,
- HttpServletResponse response,
- AccessDeniedException e) throws IOException, ServletException {
- response.setCharacterEncoding("UTF-8");
- response.setContentType("application/json");
- response.getWriter().println(JSONUtil.parse(CommonResult.forbidden(e.getMessage())));
- response.getWriter().flush();
- }
-}
diff --git a/mall-admin/src/main/java/com/macro/mall/config/MallSecurityConfig.java b/mall-admin/src/main/java/com/macro/mall/config/MallSecurityConfig.java
new file mode 100644
index 0000000..a82ea2e
--- /dev/null
+++ b/mall-admin/src/main/java/com/macro/mall/config/MallSecurityConfig.java
@@ -0,0 +1,29 @@
+package com.macro.mall.config;
+
+import com.macro.mall.security.config.SecurityConfig;
+import com.macro.mall.service.UmsAdminService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.core.userdetails.UserDetailsService;
+
+/**
+ * mall-security模块相关配置
+ * Created by macro on 2019/11/9.
+ */
+@Configuration
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(prePostEnabled=true)
+public class MallSecurityConfig extends SecurityConfig {
+
+ @Autowired
+ private UmsAdminService adminService;
+
+ @Bean
+ public UserDetailsService userDetailsService() {
+ //获取登录用户信息
+ return username -> adminService.loadUserByUsername(username);
+ }
+}
diff --git a/mall-admin/src/main/java/com/macro/mall/config/SecurityConfig.java b/mall-admin/src/main/java/com/macro/mall/config/SecurityConfig.java
deleted file mode 100644
index 1fe13ac..0000000
--- a/mall-admin/src/main/java/com/macro/mall/config/SecurityConfig.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package com.macro.mall.config;
-
-import com.macro.mall.bo.AdminUserDetails;
-import com.macro.mall.component.JwtAuthenticationTokenFilter;
-import com.macro.mall.component.RestAuthenticationEntryPoint;
-import com.macro.mall.component.RestfulAccessDeniedHandler;
-import com.macro.mall.model.UmsAdmin;
-import com.macro.mall.model.UmsPermission;
-import com.macro.mall.service.UmsAdminService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.http.HttpMethod;
-import org.springframework.security.authentication.AuthenticationManager;
-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.core.userdetails.UserDetailsService;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
-import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
-import org.springframework.web.cors.CorsConfiguration;
-import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
-import org.springframework.web.filter.CorsFilter;
-
-import java.util.List;
-
-
-/**
- * SpringSecurity的配置
- * Created by macro on 2018/4/26.
- */
-@Configuration
-@EnableWebSecurity
-@EnableGlobalMethodSecurity(prePostEnabled=true)
-public class SecurityConfig extends WebSecurityConfigurerAdapter {
- @Autowired
- private UmsAdminService adminService;
- @Autowired
- private RestfulAccessDeniedHandler restfulAccessDeniedHandler;
- @Autowired
- private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
-
- @Override
- protected void configure(HttpSecurity httpSecurity) throws Exception {
- httpSecurity.csrf()// 由于使用的是JWT,我们这里不需要csrf
- .disable()
- .sessionManagement()// 基于token,所以不需要session
- .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
- .and()
- .authorizeRequests()
- .antMatchers(HttpMethod.GET, // 允许对于网站静态资源的无授权访问
- "/",
- "/*.html",
- "/favicon.ico",
- "/**/*.html",
- "/**/*.css",
- "/**/*.js",
- "/swagger-resources/**",
- "/v2/api-docs/**",
- "/webjars/springfox-swagger-ui/**"
- )
- .permitAll()
- .antMatchers("/admin/login", "/admin/register")// 对登录注册要允许匿名访问
- .permitAll()
- .antMatchers(HttpMethod.OPTIONS)//跨域请求会先进行一次options请求
- .permitAll()
-// .antMatchers("/**")//测试时全部运行访问
-// .permitAll()
- .anyRequest()// 除上面外的所有请求全部需要鉴权认证
- .authenticated();
- // 禁用缓存
- httpSecurity.headers().cacheControl();
- // 添加JWT filter
- httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
- //添加自定义未授权和未登录结果返回
- httpSecurity.exceptionHandling()
- .accessDeniedHandler(restfulAccessDeniedHandler)
- .authenticationEntryPoint(restAuthenticationEntryPoint);
- }
-
- @Override
- protected void configure(AuthenticationManagerBuilder auth) throws Exception {
- auth.userDetailsService(userDetailsService())
- .passwordEncoder(passwordEncoder());
- }
-
- @Bean
- public PasswordEncoder passwordEncoder() {
- return new BCryptPasswordEncoder();
- }
-
- @Bean
- public UserDetailsService userDetailsService() {
- //获取登录用户信息
- return username -> {
- UmsAdmin admin = adminService.getAdminByUsername(username);
- if (admin != null) {
- List permissionList = adminService.getPermissionList(admin.getId());
- return new AdminUserDetails(admin,permissionList);
- }
- throw new UsernameNotFoundException("用户名或密码错误");
- };
- }
-
- @Bean
- public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter(){
- return new JwtAuthenticationTokenFilter();
- }
-
- @Bean
- @Override
- public AuthenticationManager authenticationManagerBean() throws Exception {
- return super.authenticationManagerBean();
- }
-
-}
diff --git a/mall-admin/src/main/java/com/macro/mall/service/UmsAdminService.java b/mall-admin/src/main/java/com/macro/mall/service/UmsAdminService.java
index 520b1a8..ebf0cd4 100644
--- a/mall-admin/src/main/java/com/macro/mall/service/UmsAdminService.java
+++ b/mall-admin/src/main/java/com/macro/mall/service/UmsAdminService.java
@@ -5,6 +5,7 @@ import com.macro.mall.dto.UpdateAdminPasswordParam;
import com.macro.mall.model.UmsAdmin;
import com.macro.mall.model.UmsPermission;
import com.macro.mall.model.UmsRole;
+import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@@ -84,4 +85,9 @@ public interface UmsAdminService {
* 修改密码
*/
int updatePassword(UpdateAdminPasswordParam updatePasswordParam);
+
+ /**
+ * 获取用户信息
+ */
+ UserDetails loadUserByUsername(String username);
}
diff --git a/mall-admin/src/main/java/com/macro/mall/service/impl/UmsAdminServiceImpl.java b/mall-admin/src/main/java/com/macro/mall/service/impl/UmsAdminServiceImpl.java
index 65cf5f5..eeb0613 100644
--- a/mall-admin/src/main/java/com/macro/mall/service/impl/UmsAdminServiceImpl.java
+++ b/mall-admin/src/main/java/com/macro/mall/service/impl/UmsAdminServiceImpl.java
@@ -3,6 +3,7 @@ package com.macro.mall.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.PageHelper;
+import com.macro.mall.bo.AdminUserDetails;
import com.macro.mall.dao.UmsAdminPermissionRelationDao;
import com.macro.mall.dao.UmsAdminRoleRelationDao;
import com.macro.mall.dto.UmsAdminParam;
@@ -12,20 +13,18 @@ import com.macro.mall.mapper.UmsAdminMapper;
import com.macro.mall.mapper.UmsAdminPermissionRelationMapper;
import com.macro.mall.mapper.UmsAdminRoleRelationMapper;
import com.macro.mall.model.*;
+import com.macro.mall.security.util.JwtTokenUtil;
import com.macro.mall.service.UmsAdminService;
-import com.macro.mall.util.JwtTokenUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
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.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
@@ -47,15 +46,9 @@ import java.util.stream.Collectors;
public class UmsAdminServiceImpl implements UmsAdminService {
private static final Logger LOGGER = LoggerFactory.getLogger(UmsAdminServiceImpl.class);
@Autowired
- private AuthenticationManager authenticationManager;
- @Autowired
- private UserDetailsService userDetailsService;
- @Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private PasswordEncoder passwordEncoder;
- @Value("${jwt.tokenHead}")
- private String tokenHead;
@Autowired
private UmsAdminMapper adminMapper;
@Autowired
@@ -105,7 +98,7 @@ public class UmsAdminServiceImpl implements UmsAdminService {
String token = null;
//密码需要客户端加密后传递
try {
- UserDetails userDetails = userDetailsService.loadUserByUsername(username);
+ UserDetails userDetails = loadUserByUsername(username);
if(!passwordEncoder.matches(password,userDetails.getPassword())){
throw new BadCredentialsException("密码不正确");
}
@@ -148,11 +141,7 @@ public class UmsAdminServiceImpl implements UmsAdminService {
@Override
public String refreshToken(String oldToken) {
- String token = oldToken.substring(tokenHead.length());
- if (jwtTokenUtil.canRefresh(token)) {
- return jwtTokenUtil.refreshToken(token);
- }
- return null;
+ return jwtTokenUtil.refreshHeadToken(oldToken);
}
@Override
@@ -274,4 +263,15 @@ public class UmsAdminServiceImpl implements UmsAdminService {
adminMapper.updateByPrimaryKey(umsAdmin);
return 1;
}
+
+ @Override
+ public UserDetails loadUserByUsername(String username){
+ //获取用户信息
+ UmsAdmin admin = getAdminByUsername(username);
+ if (admin != null) {
+ List permissionList = getPermissionList(admin.getId());
+ return new AdminUserDetails(admin,permissionList);
+ }
+ throw new UsernameNotFoundException("用户名或密码错误");
+ }
}
diff --git a/mall-admin/src/main/java/com/macro/mall/util/JwtTokenUtil.java b/mall-admin/src/main/java/com/macro/mall/util/JwtTokenUtil.java
deleted file mode 100644
index 15bcbf1..0000000
--- a/mall-admin/src/main/java/com/macro/mall/util/JwtTokenUtil.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package com.macro.mall.util;
-
-import io.jsonwebtoken.*;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.stereotype.Component;
-
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * JwtToken生成的工具类
- * JWT token的格式:header.payload.signature
- * header的格式(算法、token的类型):
- * {"alg": "HS512","typ": "JWT"}
- * payload的格式(用户名、创建时间、生成时间):
- * {"sub":"wang","created":1489079981393,"exp":1489684781}
- * signature的生成算法:
- * HMACSHA512(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
- * Created by macro on 2018/4/26.
- */
-@Component
-public class JwtTokenUtil {
- private static final Logger LOGGER = LoggerFactory.getLogger(JwtTokenUtil.class);
- private static final String CLAIM_KEY_USERNAME = "sub";
- private static final String CLAIM_KEY_CREATED = "created";
- @Value("${jwt.secret}")
- private String secret;
- @Value("${jwt.expiration}")
- private Long expiration;
-
- /**
- * 根据负责生成JWT的token
- */
- private String generateToken(Map claims) {
- return Jwts.builder()
- .setClaims(claims)
- .setExpiration(generateExpirationDate())
- .signWith(SignatureAlgorithm.HS512, secret)
- .compact();
- }
-
- /**
- * 从token中获取JWT中的负载
- */
- private Claims getClaimsFromToken(String token) {
- Claims claims = null;
- try {
- claims = Jwts.parser()
- .setSigningKey(secret)
- .parseClaimsJws(token)
- .getBody();
- } catch (Exception e) {
- LOGGER.info("JWT格式验证失败:{}",token);
- }
- return claims;
- }
-
- /**
- * 生成token的过期时间
- */
- private Date generateExpirationDate() {
- return new Date(System.currentTimeMillis() + expiration * 1000);
- }
-
- /**
- * 从token中获取登录用户名
- */
- public String getUserNameFromToken(String token) {
- String username;
- try {
- Claims claims = getClaimsFromToken(token);
- username = claims.getSubject();
- } catch (Exception e) {
- username = null;
- }
- return username;
- }
-
- /**
- * 验证token是否还有效
- *
- * @param token 客户端传入的token
- * @param userDetails 从数据库中查询出来的用户信息
- */
- public boolean validateToken(String token, UserDetails userDetails) {
- String username = getUserNameFromToken(token);
- return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
- }
-
- /**
- * 判断token是否已经失效
- */
- private boolean isTokenExpired(String token) {
- Date expiredDate = getExpiredDateFromToken(token);
- return expiredDate.before(new Date());
- }
-
- /**
- * 从token中获取过期时间
- */
- private Date getExpiredDateFromToken(String token) {
- Claims claims = getClaimsFromToken(token);
- return claims.getExpiration();
- }
-
- /**
- * 根据用户信息生成token
- */
- public String generateToken(UserDetails userDetails) {
- Map claims = new HashMap<>();
- claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
- claims.put(CLAIM_KEY_CREATED, new Date());
- return generateToken(claims);
- }
-
- /**
- * 判断token是否可以被刷新
- */
- public boolean canRefresh(String token) {
- return !isTokenExpired(token);
- }
-
- /**
- * 刷新token
- */
- public String refreshToken(String token) {
- Claims claims = getClaimsFromToken(token);
- claims.put(CLAIM_KEY_CREATED, new Date());
- return generateToken(claims);
- }
-}
diff --git a/mall-admin/src/main/resources/application.yml b/mall-admin/src/main/resources/application.yml
index 99a7022..c0b10c0 100644
--- a/mall-admin/src/main/resources/application.yml
+++ b/mall-admin/src/main/resources/application.yml
@@ -9,9 +9,24 @@ mybatis:
jwt:
tokenHeader: Authorization #JWT存储的请求头
- secret: mySecret #JWT加解密使用的密钥
+ secret: mall-admin-secret #JWT加解密使用的密钥
expiration: 604800 #JWT的超期限时间(60*60*24)
tokenHead: Bearer #JWT负载中拿到开头
+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
aliyun:
oss:
diff --git a/pom.xml b/pom.xml
index dc1af27..c8b7ded 100644
--- a/pom.xml
+++ b/pom.xml
@@ -44,6 +44,7 @@
4.8
1.0-SNAPSHOT
1.0-SNAPSHOT
+ 1.0-SNAPSHOT
@@ -88,6 +89,12 @@
mall-mbg
${mall-mbg.version}
+
+
+ com.macro.mall
+ mall-security
+ ${mall-security.version}
+
com.github.pagehelper