- SpringBoot 整合security 实现自定义Token
- SpringBoot 整合security 实现自定义Token
- SpringBoot 整合security 实现自定义Token
- SpringBoot +Spring Security + th
- 整合springboot + security + druid
- Spring Secutity 添加过滤器实现自定义登录认证
- Spring Security 整合 JSON Web Toke
- Spring Security 整合 JSON Web Toke
- SpringBoot入门建站全系列(十二)Spring Secu
- SpringBoot 整合mongoDB并自定义连接池
1.数据库创建****
创建user表
创建user_token表,管理用户的tonken信息

2.创建对Token和用户信息操作的service及实体类
话不多说,直接上代码
TokenInfo.java
/**
* Token信息
*/
public class TokenInfo {
private Integer userId;
private String accessToken;
private String clientId;
private String ip;
private LocalDateTime updateTime;
...
userInfo
/**
* 用户信息
*/
public class UserInfo {
private String userId;
private String username;
private String role;
private String realName;
private String password;
...
service(实现类,接口就不写了)
TokenServiceImpl.java
@Service
@SuppressWarnings("all")
public class TokenServiceImpl implements TokenService {
@Autowired
private TokenMapper tokenMapper;
/**
* 过期时间5分钟
*/
private static final long EXPIRE_TIME = 5 * 60 * 1000;
/**
* 加密密钥
*/
private static final String KEY = "demo";
@Override
public TokenInfo findByUserId(String userId) {
return tokenMapper.findByUserId(userId);
}
@Override
public TokenInfo findByClientId(String clientId) {
return tokenMapper.findByClientId(clientId);
}
@Override
public TokenInfo createToken(UserDetailsInfo userInfo) {
TokenInfo tokenInfo = new TokenInfo();
Map<String, Object> header = new HashMap();
header.put("typ", "JWT");
header.put("alg", "HS256");
//setID:用户ID
//setExpiration:token过期时间 当前时间+有效时间
//setSubject:用户名
//setIssuedAt:token创建时间
//signWith:加密方式
JwtBuilder builder = Jwts.builder().setHeader(header)
.setId(userInfo.getUserId())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE_TIME))
.setSubject(userInfo.getUsername())
.setIssuedAt(new Date())
.signWith(SignatureAlgorithm.HS256, KEY);
tokenInfo.setAccessToken(builder.compact());
tokenInfo.setIp(userInfo.getIp());
tokenInfo.setUserId(Integer.valueOf(userInfo.getUserId()));
String clientId = "";
// 根据数据库的用户信息查询Token
TokenInfo accesstoken = tokenMapper.findByUserId(userInfo.getUserId());
if (accesstoken != null && equal(accesstoken.getIp(), userInfo.getIp())) {
clientId = accesstoken.getClientId();
tokenInfo.setClientId(clientId);
// 更新Token信息
tokenMapper.updateToken(tokenInfo);
} else {
clientId = UUID.randomUUID().toString();
tokenInfo.setClientId(clientId);
// 登陆Token信息
tokenMapper.addToken(tokenInfo);
}
return tokenInfo;
}
@Override
public void updateToken(TokenInfo token) {
tokenMapper.updateToken(token);
}
@Override
public void deleteToken(String clientId) {
tokenMapper.deleteToken(clientId);
}
@Override
public boolean checkToken(TokenInfo tokenInfo) {
//根据ClientId查找数据库Token
TokenInfo myToken = tokenMapper.findByClientId(tokenInfo.getClientId());
if (myToken != null && tokenInfo.getAccessToken().
equals(myToken.getAccessToken())) {
Claims claims = null;
try {
//token过期后,会抛出ExpiredJwtException 异常,通过这个来判定token过期,
claims = Jwts.parser().setSigningKey(KEY).parseClaimsJws(tokenInfo.getAccessToken()).getBody();
} catch (ExpiredJwtException e) {
return false;
}
return true;
}
return false;
}
}
UserServiceImpl.java
@Service
@SuppressWarnings("all")
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public UserInfo findByUserId(Integer userId) {
return userMapper.findByUserId(userId);
}
@Override
public UserInfo findByUserName(String userName) {
return userMapper.findByUserName(userName);
}
@Override
public List<UserInfo> selectAll() {
return userMapper.selectAll();
}
}
3.工具类创建
SecurityUtils.java
/**
* Security工具类
*/
public class SecurityUtils {
private static final String MD5_KEY = "0123456789AbCDeF";
/**
* 获取当前登录信息
* @return
*/
public static Authentication getAuthentication() {
if (SecurityContextHolder.getContext() != null) {
return SecurityContextHolder.getContext().getAuthentication();
}
return null;
}
public static void setAuthentication(Authentication authentication) {
if (SecurityContextHolder.getContext() != null) {
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
public static Integer getUserId() {
Integer userId = null;
Authentication authentication = getAuthentication();
if (authentication != null) {
Object principal = authentication.getPrincipal();
if (principal != null && principal instanceof UserDetailsInfo) {
userId = Integer.valueOf(((UserDetailsInfo) principal).getUserId());
}
}
return userId;
}
public static String getUsername() {
String userName = null;
Authentication authentication = getAuthentication();
if (authentication != null) {
Object principal = authentication.getPrincipal();
if (principal != null && principal instanceof UserDetails) {
userName = ((UserDetails) principal).getUsername();
}
}
return userName;
}
public static boolean hasRole(String role) {
if (SecurityContextHolder.getContext() == null) {
return false;
}
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
if (role.equals(grantedAuthority.getAuthority())) {
return true;
}
}
return false;
}
}
ClientIdUtil.java
public class ClientIdUtil {
/**
* 用户ip获取
* @param request
* @return
*/
public static String getIp(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if (ip.equals("0:0:0:0:0:0:0:1")) {
ip = "127.0.0.1";
}
return ip;
}
}
MD5Util.java
/**
* MD5加密
* @author:admin
* @date:Created at 2020/12/13
*/
public class MD5Util {
public static String MD5(String s) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] bytes = md.digest(s.getBytes("utf-8"));
return toHex(bytes);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static String toHex(byte[] bytes) {
final char[] HEX_DIGITS = "0123456789AbCDeF".toCharArray();
StringBuilder ret = new StringBuilder(bytes.length * 2);
for (int i = 0; i < bytes.length; i++) {
ret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);
ret.append(HEX_DIGITS[bytes[i] & 0x0f]);
}
return ret.toString();
}
/**
* 密码加强版
*
* @param str
* @return
*/
public static String MD55(String str) {
String pwd1 = MD5Util.MD5(str);
return pwd1.substring(0, 10) + pwd1.substring(22) + pwd1.substring(10, 22);
}
}
4.实现UserDetailsService
UserDetailsInfo.java
public class UserDetailsInfo extends User {
private String userId;
private String role;
private String realName;
private String ip;
...
DemoUserDetailsService.java
/**
* 通过用户名取得用户信息
*/
@Service
@SuppressWarnings("all")
public class DemoUserDetailsService implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
Collection<GrantedAuthority> authorities = new ArrayList<>();
// 取得数据库中的用户信息
UserInfo user = userService.findByUserName(userName);
// 用户不存在
if (user == null) {
throw new UsernameNotFoundException("user is not exist");
}
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(user.getRole());
authorities.add(grantedAuthority);
// 设置UserDetailsInfo用户信息
UserDetailsInfo userDetails = new UserDetailsInfo(user.getUserId(),
user.getUsername(),user.getPassword(),authorities);
return userDetails;
}
}
4.用户身份验证
DemoAuthenticationProvider.java
/**
* 用户身份验证
* @author:zhuolun.he
* @date:Created at 2020/12/13
*/
@Component
@SuppressWarnings("all")
public class DemoAuthenticationProvider implements AuthenticationProvider {
@Autowired
private DemoUserDetailsService demoUserDetailsService;
/**
* 自定义验证方式
* @param authentication 认证信息
* @return 用户认证信息
* @throws AuthenticationException
*/
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
//认证信息取得
String username = authentication.getName();
String password = (String) authentication.getCredentials();
// 获取用户信息
UserDetails user = demoUserDetailsService.loadUserByUsername(username);
if (user ==null) {
throw new BadCredentialsException("Username not found");
}
try {
// 验证密码(MD5加密)
password = MD5Util.MD5(password);
} catch (Exception e){
throw new BadCredentialsException("Password encode failed");
}
// 判断用户密码是否正确
if (!password.equals(user.getPassword())) {
throw new BadCredentialsException("Wrong password");
}
// 用户认证信息设定
Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
UsernamePasswordAuthenticationToken userInfo = new
UsernamePasswordAuthenticationToken(user,password,authorities);
userInfo.setDetails(user);
return userInfo;
}
@Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
}
5.过滤器创建
SecurityFilter.java
/**
* 过滤器
*/
public class SecurityFilter implements Filter {
private Logger logger = LoggerFactory.getLogger(SecurityFilter.class);
@Autowired
private TokenService tokenService;
/**
* 放行的url:login/logout
*/
@Value("${spring.security.url}")
private String[] urls;
private static final String FILTER_APPLIED = "_spring_security_filterSecurityInterceptor_filterApplied";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("init in Security");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if (request.getAttribute(FILTER_APPLIED) != null) {
filterChain.doFilter(request, response);
return;
}
request.setAttribute(FILTER_APPLIED, true);
HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
// url放行
for (String doUrl : urls) {
if (httpRequest.getRequestURI().endsWith(doUrl)) {
filterChain.doFilter(request, response);
return;
}
}
// 用户信息过滤
Object userInfo = SecurityUtils.getAuthentication().getPrincipal();
if (userInfo == null || !(userInfo instanceof UserDetailsInfo)) {
response.setContentType("application/json;charset=UTF-8");
ResultData data = new ResultData(0,"Security authentication invalid");
response.getWriter().write((new Gson()).toJson(data));
return;
}
// clientId和accessToken取得
String clientId = httpRequest.getHeader("clientId");
String accessToken = httpRequest.getHeader("accessToken");
TokenInfo tokenInfo = new TokenInfo();
tokenInfo.setClientId(clientId);
tokenInfo.setAccessToken(accessToken);
// 对Token验证过滤
if (!tokenService.checkToken(tokenInfo)) {
response.setContentType("application/json;charset=UTF-8");
ResultData data = new ResultData(0,"Security authentication invalid");
response.getWriter().write((new Gson()).toJson(data));
return;
}
filterChain.doFilter(request, response);
}
@Override
public void destroy() {}
}
网友评论