JWT认证授权功能完善

This commit is contained in:
zhh 2018-04-23 16:02:02 +08:00
parent cd1dd9190a
commit b0a945d242
10 changed files with 280 additions and 25 deletions

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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);
}
}

View File

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

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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===