瀏覽代碼

JWT认证授权功能完善

zhh 7 年之前
父節點
當前提交
b0a945d242

+ 1 - 1
mall-admin/src/main/java/com/macro/mall/component/BindingResultAspect.java

@@ -27,7 +27,7 @@ public class BindingResultAspect {
             if (arg instanceof BindingResult) {
                 BindingResult result = (BindingResult) arg;
                 if (result.hasErrors()) {
-                    return new CommonResult().validateFailed(result.getFieldError().getDefaultMessage());
+                    return new CommonResult().validateFailed(result);
                 }
             }
         }

+ 8 - 2
mall-admin/src/main/java/com/macro/mall/config/SecurityConfig.java

@@ -9,6 +9,7 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.http.HttpMethod;
 import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
+import org.springframework.security.authentication.encoding.PasswordEncoder;
 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@@ -48,7 +49,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
                        "/v2/api-docs/**"
                        )
                .permitAll()
-               .antMatchers("/auth/**")// 对于获取token的rest api要允许匿名访问
+               .antMatchers("/admin/**")// 对于获取token的rest api要允许匿名访问
                .permitAll()
                .anyRequest()// 除上面外的所有请求全部需要鉴权认证
                .authenticated();
@@ -61,7 +62,12 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
     @Override
     protected void configure(AuthenticationManagerBuilder auth) throws Exception {
         auth.userDetailsService(userDetailsService())
-                .passwordEncoder(new Md5PasswordEncoder());
+                .passwordEncoder(passwordEncoder());
+    }
+
+    @Bean
+    public PasswordEncoder passwordEncoder(){
+        return new Md5PasswordEncoder();
     }
 
     @Bean

+ 66 - 0
mall-admin/src/main/java/com/macro/mall/controller/UmsAdminController.java

@@ -0,0 +1,66 @@
+package com.macro.mall.controller;
+
+import com.macro.mall.dto.CommonResult;
+import com.macro.mall.dto.UmsAdminLoginParam;
+import com.macro.mall.dto.UmsAdminParam;
+import com.macro.mall.model.UmsAdmin;
+import com.macro.mall.service.UmsAdminService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Controller;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 后台用户管理
+ */
+@Controller
+@Api(tags = "UmsAdminController", description = "后台用户管理")
+@RequestMapping("/admin")
+public class UmsAdminController {
+    @Autowired
+    private UmsAdminService adminService;
+    @Value("${jwt.tokenHeader}")
+    private String tokenHeader;
+
+    @ApiOperation(value = "用户注册")
+    @RequestMapping(value = "/register", method = RequestMethod.POST)
+    @ResponseBody
+    public Object register(@RequestBody UmsAdminParam umsAdminParam, BindingResult result) {
+        UmsAdmin umsAdmin = adminService.register(umsAdminParam);
+        if (umsAdmin == null) {
+            new CommonResult().failed();
+        }
+        return new CommonResult().success(umsAdmin);
+    }
+
+    @ApiOperation(value = "登录以后返回token")
+    @RequestMapping(value = "/login", method = RequestMethod.POST)
+    @ResponseBody
+    public Object login(@RequestBody UmsAdminLoginParam umsAdminLoginParam, BindingResult result) {
+        String token = adminService.login(umsAdminLoginParam.getUsername(), umsAdminLoginParam.getPassword());
+        if (token == null) {
+            new CommonResult().failed();
+        }
+        return new CommonResult().success(token);
+    }
+
+    @ApiOperation(value = "刷新token")
+    @RequestMapping(value = "/token/refresh", method = RequestMethod.GET)
+    @ResponseBody
+    public Object refreshToken(HttpServletRequest request) {
+        String token = request.getHeader(tokenHeader);
+        String refreshToken = adminService.refreshToken(token);
+        if (refreshToken == null) {
+            return new CommonResult().failed();
+        }
+        return new CommonResult().success(token);
+    }
+}

+ 0 - 1
mall-admin/src/main/java/com/macro/mall/dto/PmsBrandParam.java

@@ -11,7 +11,6 @@ import javax.validation.constraints.NotNull;
 /**
  * 品牌传递参数
  */
-@ApiModel(value = "PmsBrandParam")
 public class PmsBrandParam {
     @ApiModelProperty(value = "品牌名称",required = true)
     @NotEmpty(message = "名称不能为空")

+ 32 - 0
mall-admin/src/main/java/com/macro/mall/dto/UmsAdminLoginParam.java

@@ -0,0 +1,32 @@
+package com.macro.mall.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import org.hibernate.validator.constraints.NotEmpty;
+
+/**
+ * 用户登录参数
+ */
+public class UmsAdminLoginParam {
+    @ApiModelProperty(value = "用户名", required = true)
+    @NotEmpty(message = "用户名不能为空")
+    private String username;
+    @ApiModelProperty(value = "密码", required = true)
+    @NotEmpty(message = "密码不能为空")
+    private String password;
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+}

+ 54 - 0
mall-admin/src/main/java/com/macro/mall/dto/UmsAdminParam.java

@@ -0,0 +1,54 @@
+package com.macro.mall.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import org.hibernate.validator.constraints.Email;
+import org.hibernate.validator.constraints.NotEmpty;
+
+/**
+ * 用户登录参数
+ */
+public class UmsAdminParam {
+    @ApiModelProperty(value = "用户名", required = true)
+    @NotEmpty(message = "用户名不能为空")
+    private String username;
+    @ApiModelProperty(value = "密码", required = true)
+    @NotEmpty(message = "密码不能为空")
+    private String password;
+    @ApiModelProperty(value = "用户头像")
+    private String icon;
+    @ApiModelProperty(value = "邮箱")
+    @Email(message = "邮箱格式不合法")
+    private String email;
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getIcon() {
+        return icon;
+    }
+
+    public void setIcon(String icon) {
+        this.icon = icon;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+}

+ 20 - 0
mall-admin/src/main/java/com/macro/mall/service/UmsAdminService.java

@@ -1,5 +1,6 @@
 package com.macro.mall.service;
 
+import com.macro.mall.dto.UmsAdminParam;
 import com.macro.mall.model.UmsAdmin;
 
 /**
@@ -10,4 +11,23 @@ public interface UmsAdminService {
      * 根据用户名获取后台管理员
      */
     UmsAdmin getAdminByUsername(String username);
+
+    /**
+     * 注册功能
+     */
+    UmsAdmin register(UmsAdminParam umsAdminParam);
+
+    /**
+     * 登录功能
+     * @param username 用户名
+     * @param password 密码
+     * @return 生成的JWT的token
+     */
+    String login(String username,String password);
+
+    /**
+     * 刷新token的功能
+     * @param oldToken 旧的token
+     */
+    String refreshToken(String oldToken);
 }

+ 58 - 0
mall-admin/src/main/java/com/macro/mall/service/impl/UmsAdminServiceImpl.java

@@ -1,10 +1,21 @@
 package com.macro.mall.service.impl;
 
+import com.macro.mall.dto.UmsAdminParam;
 import com.macro.mall.mapper.UmsAdminMapper;
 import com.macro.mall.model.UmsAdmin;
 import com.macro.mall.model.UmsAdminExample;
 import com.macro.mall.service.UmsAdminService;
+import com.macro.mall.util.JwtTokenUtil;
+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.UsernamePasswordAuthenticationToken;
+import org.springframework.security.authentication.encoding.PasswordEncoder;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
@@ -16,6 +27,17 @@ import java.util.List;
 public class UmsAdminServiceImpl implements UmsAdminService{
     @Autowired
     private UmsAdminMapper adminMapper;
+    @Autowired
+    private AuthenticationManager authenticationManager;
+    @Autowired
+    private UserDetailsService userDetailsService;
+    @Autowired
+    private JwtTokenUtil jwtTokenUtil;
+    @Autowired
+    private PasswordEncoder passwordEncoder;
+    @Value("${jwt.tokenHead}")
+    private String tokenHead;
+
     @Override
     public UmsAdmin getAdminByUsername(String username) {
         UmsAdminExample example = new UmsAdminExample();
@@ -26,4 +48,40 @@ public class UmsAdminServiceImpl implements UmsAdminService{
         }
         return null;
     }
+
+    @Override
+    public UmsAdmin register(UmsAdminParam umsAdminParam) {
+        UmsAdmin umsAdmin = new UmsAdmin();
+        BeanUtils.copyProperties(umsAdminParam,umsAdmin);
+        //查询是否有相同用户名的用户
+        UmsAdminExample example = new UmsAdminExample();
+        example.createCriteria().andUsernameEqualTo(umsAdmin.getUsername());
+        List<UmsAdmin> umsAdminList = adminMapper.selectByExample(example);
+        if(umsAdminList.size()>0){
+            return null;
+        }
+        //将密码进行加密操作
+        String md5Password = passwordEncoder.encodePassword(umsAdmin.getPassword(), null);
+        umsAdmin.setPassword(md5Password);
+        adminMapper.insert(umsAdmin);
+        return umsAdmin;
+    }
+
+    @Override
+    public String login(String username, String password) {
+        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username,password);
+        Authentication authentication = authenticationManager.authenticate(authenticationToken);
+        SecurityContextHolder.getContext().setAuthentication(authentication);
+        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
+        return jwtTokenUtil.generateToken(userDetails);
+    }
+
+    @Override
+    public String refreshToken(String oldToken) {
+        String token = oldToken.substring(tokenHead.length());
+        if(jwtTokenUtil.canRefresh(token)){
+            return jwtTokenUtil.refreshToken(token);
+        }
+        return null;
+    }
 }

+ 39 - 19
mall-admin/src/main/java/com/macro/mall/util/JwtTokenUtil.java

@@ -1,13 +1,14 @@
 package com.macro.mall.util;
 
-import io.jsonwebtoken.Claims;
-import io.jsonwebtoken.Jwts;
-import io.jsonwebtoken.SignatureAlgorithm;
+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;
 
 /**
@@ -22,6 +23,7 @@ import java.util.Map;
  */
 @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}")
@@ -32,26 +34,26 @@ public class JwtTokenUtil {
     /**
      * 根据负责生成JWT的token
      */
-    String generateToken(Map<String, Object> claims) {
+    private String generateToken(Map<String, Object> claims) {
         return Jwts.builder()
                 .setClaims(claims)
                 .setExpiration(generateExpirationDate())
-                .signWith(SignatureAlgorithm.RS512, secret)
+                .signWith(SignatureAlgorithm.HS512, secret)
                 .compact();
     }
 
     /**
      * 从token中获取JWT中的负载
      */
-    Claims getClaimsFromToken(String token) {
-        Claims claims;
+    private Claims getClaimsFromToken(String token) {
+        Claims claims = null;
         try {
             claims = Jwts.parser()
                     .setSigningKey(secret)
                     .parseClaimsJws(token)
                     .getBody();
-        } finally {
-            claims = null;
+        } catch (Exception e) {
+            LOGGER.info("JWT格式验证失败:{}",token);
         }
         return claims;
     }
@@ -70,9 +72,8 @@ public class JwtTokenUtil {
         String username;
         try {
             Claims claims = getClaimsFromToken(token);
-            username = claims.getSubject();
+            username =  claims.getSubject();
         } catch (Exception e) {
-            e.printStackTrace();
             username = null;
         }
         return username;
@@ -101,14 +102,33 @@ public class JwtTokenUtil {
      * 从token中获取过期时间
      */
     private Date getExpiredDateFromToken(String token) {
-        Date expiredDate = null;
-        try {
-            Claims claims = getClaimsFromToken(token);
-            expiredDate = claims.getExpiration();
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-        return expiredDate;
+        Claims claims = getClaimsFromToken(token);
+        return claims.getExpiration();
+    }
+
+    /**
+     * 根据用户信息生成token
+     */
+    public String generateToken(UserDetails userDetails) {
+        Map<String, Object> 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);
+    }
 }

+ 2 - 2
mall-admin/src/main/resources/application.properties

@@ -32,8 +32,8 @@ spring.thymeleaf.cache=false
 jwt.tokenHeader=Authorization
 #JWT加解密使用的密钥
 jwt.secret=mySecret
-#JWT的超期限时间
+#JWT的超期限时间(60*60*24)
 jwt.expiration=604800
 #JWT负载中拿到开头
-jwt.tokenHead="Bearer "
+jwt.tokenHead=Bearer 
 #===JWT end===