package me.zhengjie.core.security;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails; import java.sql.Timestamp;
import java.util.*; /**
* @author jie
* @date 2018-11-23
*/
@Getter
@AllArgsConstructor
public class JwtUser implements UserDetails { @JsonIgnore
private final Long id; private final String username; @JsonIgnore
private final String password; private final String avatar; private final String email; @JsonIgnore
private final Collection<? extends GrantedAuthority> authorities; private final boolean enabled; private Timestamp createTime; @JsonIgnore
private final Date lastPasswordResetDate; @JsonIgnore
@Override
public boolean isAccountNonExpired() {
return true;
} @JsonIgnore
@Override
public boolean isAccountNonLocked() {
return true;
} @JsonIgnore
@Override
public boolean isCredentialsNonExpired() {
return true;
} @JsonIgnore
@Override
public String getPassword() {
return password;
} @Override
public boolean isEnabled() {
return enabled;
} /**
* 在我们保存权限的时候加上了前缀ROLE_,因此在这里需要处理下数据
* @return
*/
public Collection getRoles() {
Set<String> roles = new LinkedHashSet<>();
for (GrantedAuthority authority : authorities) {
roles.add(authority.getAuthority().substring(5));
}
return roles;
}
}
package me.zhengjie.core.security;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Serializable; @Component
public class
JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable { private static final long serialVersionUID = -8970718410437077606L; @Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
/**
* 当用户尝试访问安全的REST资源而不提供任何凭据时,将调用此方法发送401 响应
*/
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException==null?"Unauthorized":authException.getMessage());
}
}
package me.zhengjie.core.security;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Serializable; @Component
public class
JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable { private static final long serialVersionUID = -8970718410437077606L; @Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
/**
* 当用户尝试访问安全的REST资源而不提供任何凭据时,将调用此方法发送401 响应
*/
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException==null?"Unauthorized":authException.getMessage());
}
}
package me.zhengjie.core.security;

import io.jsonwebtoken.ExpiredJwtException;
import me.zhengjie.core.utils.JwtTokenUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
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; @Component
public class JwtAuthorizationTokenFilter extends OncePerRequestFilter { private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final UserDetailsService userDetailsService;
private final JwtTokenUtil jwtTokenUtil;
private final String tokenHeader; public JwtAuthorizationTokenFilter(@Qualifier("jwtUserDetailsService") UserDetailsService userDetailsService, JwtTokenUtil jwtTokenUtil, @Value("${jwt.header}") String tokenHeader) {
this.userDetailsService = userDetailsService;
this.jwtTokenUtil = jwtTokenUtil;
this.tokenHeader = tokenHeader;
} @Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
logger.debug("processing authentication for '{}'", request.getRequestURL()); final String requestHeader = request.getHeader(this.tokenHeader); String username = null;
String authToken = null;
if (requestHeader != null && requestHeader.startsWith("Bearer ")) {
authToken = requestHeader.substring(7);
try {
username = jwtTokenUtil.getUsernameFromToken(authToken);
} catch (ExpiredJwtException e) {
logger.error(e.getMessage());
}
} logger.debug("checking authentication for user '{}'", username); if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
logger.debug("security context was null, so authorizating user"); // It is not compelling necessary to load the use details from the database. You could also store the information
// in the token and read it from it. It's up to you ;)
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); // For simple validation it is completely sufficient to just check the token integrity. You don't have to call
// the database compellingly. Again it's up to you ;)
if (jwtTokenUtil.validateToken(authToken, userDetails)) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
logger.info("authorizated user '{}', setting security context", username);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
chain.doFilter(request, response);
}
}
package me.zhengjie.core.service;

import me.zhengjie.common.exception.EntityNotFoundException;
import me.zhengjie.common.utils.ValidationUtil;
import me.zhengjie.core.security.JwtUser;
import me.zhengjie.system.domain.Permission;
import me.zhengjie.system.domain.Role;
import me.zhengjie.system.domain.User;
import me.zhengjie.system.repository.PermissionRepository;
import me.zhengjie.system.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; /**
* @author jie
* @date 2018-11-22
*/
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class JwtUserDetailsService implements UserDetailsService { @Autowired
private UserRepository userRepository; @Autowired
private PermissionRepository permissionRepository; @Override
public UserDetails loadUserByUsername(String username){ User user = null;
if(ValidationUtil.isEmail(username)){
user = userRepository.findByEmail(username);
} else {
user = userRepository.findByUsername(username);
} if (user == null) {
throw new EntityNotFoundException(User.class, "name", username);
} else {
return create(user);
}
} public UserDetails create(User user) {
return new JwtUser(
user.getId(),
user.getUsername(),
user.getPassword(),
user.getAvatar(),
user.getEmail(),
mapToGrantedAuthorities(user.getRoles(),permissionRepository),
user.getEnabled(),
user.getCreateTime(),
user.getLastPasswordResetTime()
);
} private static List<GrantedAuthority> mapToGrantedAuthorities(Set<Role> roles,PermissionRepository permissionRepository) { Set<Permission> permissions = new HashSet<>();
for (Role role : roles) {
Set<Role> roleSet = new HashSet<>();
roleSet.add(role);
permissions.addAll(permissionRepository.findByRoles(roleSet));
} return permissions.stream()
.map(permission -> new SimpleGrantedAuthority("ROLE_"+permission.getName()))
.collect(Collectors.toList());
}
}
package me.zhengjie.core.service;

import me.zhengjie.common.exception.EntityNotFoundException;
import me.zhengjie.common.utils.ValidationUtil;
import me.zhengjie.core.security.JwtUser;
import me.zhengjie.system.domain.Permission;
import me.zhengjie.system.domain.Role;
import me.zhengjie.system.domain.User;
import me.zhengjie.system.repository.PermissionRepository;
import me.zhengjie.system.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; /**
* @author jie
* @date 2018-11-22
*/
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class JwtUserDetailsService implements UserDetailsService { @Autowired
private UserRepository userRepository; @Autowired
private PermissionRepository permissionRepository; @Override
public UserDetails loadUserByUsername(String username){ User user = null;
if(ValidationUtil.isEmail(username)){
user = userRepository.findByEmail(username);
} else {
user = userRepository.findByUsername(username);
} if (user == null) {
throw new EntityNotFoundException(User.class, "name", username);
} else {
return create(user);
}
} public UserDetails create(User user) {
return new JwtUser(
user.getId(),
user.getUsername(),
user.getPassword(),
user.getAvatar(),
user.getEmail(),
mapToGrantedAuthorities(user.getRoles(),permissionRepository),
user.getEnabled(),
user.getCreateTime(),
user.getLastPasswordResetTime()
);
} private static List<GrantedAuthority> mapToGrantedAuthorities(Set<Role> roles,PermissionRepository permissionRepository) { Set<Permission> permissions = new HashSet<>();
for (Role role : roles) {
Set<Role> roleSet = new HashSet<>();
roleSet.add(role);
permissions.addAll(permissionRepository.findByRoles(roleSet));
} return permissions.stream()
.map(permission -> new SimpleGrantedAuthority("ROLE_"+permission.getName()))
.collect(Collectors.toList());
}
}
package me.zhengjie.core.rest;

import lombok.extern.slf4j.Slf4j;
import me.zhengjie.common.aop.log.Log;
import me.zhengjie.core.security.AuthenticationToken;
import me.zhengjie.core.security.AuthorizationUser;
import me.zhengjie.core.utils.JwtTokenUtil;
import me.zhengjie.core.security.JwtUser;
import me.zhengjie.core.utils.EncryptUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest; /**
* @author jie
* @date 2018-11-23
* 授权、根据token获取用户详细信息
*/
@Slf4j
@RestController
@RequestMapping("auth")
public class AuthenticationController { @Value("${jwt.header}")
private String tokenHeader; @Autowired
private AuthenticationManager authenticationManager; @Autowired
private JwtTokenUtil jwtTokenUtil; @Autowired
@Qualifier("jwtUserDetailsService")
private UserDetailsService userDetailsService; /**
* 登录授权
* @param authorizationUser
* @return
*/
@Log(description = "用户登录")
@PostMapping(value = "${jwt.auth.path}")
public ResponseEntity<?> authenticationLogin(@RequestBody AuthorizationUser authorizationUser){ final UserDetails userDetails = userDetailsService.loadUserByUsername(authorizationUser.getUsername()); if(!userDetails.getPassword().equals(EncryptUtils.encryptPassword(authorizationUser.getPassword()))){
throw new AccountExpiredException("密码错误");
} if(!userDetails.isEnabled()){
throw new AccountExpiredException("账号已停用,请联系管理员");
} // 生成令牌
final String token = jwtTokenUtil.generateToken(userDetails); // 返回 token
return ResponseEntity.ok(new AuthenticationToken(token));
} /**
* 获取用户信息
* @param request
* @return
*/
@GetMapping(value = "${jwt.auth.account}")
public ResponseEntity getUserInfo(HttpServletRequest request){
JwtUser jwtUser = (JwtUser)userDetailsService.loadUserByUsername(jwtTokenUtil.getUserName(request));
return ResponseEntity.ok(jwtUser);
}
}
package me.zhengjie.core.security;

import lombok.AllArgsConstructor;
import lombok.Getter;
import java.io.Serializable; /**
* @author jie
* @date 2018-11-23
* 返回token
*/
@Getter
@AllArgsConstructor
public class AuthenticationToken implements Serializable { private final String token;
}
package me.zhengjie.core.security;

import lombok.Getter;
import lombok.Setter; import javax.validation.constraints.NotBlank; /**
* @author jie
* @date 2018-11-30
*/
@Getter
@Setter
public class AuthorizationUser { @NotBlank
private String username; @NotBlank
private String password; @Override
public String toString() {
return "{username=" + username + ", password= ******}";
}
}

JwtUser JwtAuthenticationEntryPoint JwtAuthorizationTokenFilter JwtUserDetailsService AuthenticationController的更多相关文章

  1. SpringBoot+SpringSecurity+jwt整合及初体验

    原来一直使用shiro做安全框架,配置起来相当方便,正好有机会接触下SpringSecurity,学习下这个.顺道结合下jwt,把安全信息管理的问题扔给客户端, 准备 首先用的是SpringBoot, ...

  2. 轻松上手SpringBoot Security + JWT Hello World示例

    前言 在本教程中,我们将开发一个Spring Boot应用程序,该应用程序使用JWT身份验证来保护公开的REST API.在此示例中,我们将使用硬编码的用户和密码进行用户身份验证. 在下一个教程中,我 ...

  3. WebSecurityConfig

    package me.zhengjie.core.config; import me.zhengjie.core.security.JwtAuthenticationEntryPoint; impor ...

  4. springboot2.0 web 开发标准目录架构

    ├── clean-run.sh ├── logs/ 日志文件目录 │ ├── sb2-web_test_2018-06-02_0959.0.log │ └── sb2-web_test.log | ...

  5. JWT和Spring Security集成

    通常情况下,把API直接暴露出去是风险很大的, 我们一般需要对API划分出一定的权限级别,然后做一个用户的鉴权,依据鉴权结果给予用户对应的API (一)JWT是什么,为什么要使用它? 互联网服务离不开 ...

  6. Spring Boot Security And JSON Web Token

    Spring Boot Security And JSON Web Token 说明 流程说明 何时生成和使用jwt,其实我们主要是token更有意义并携带一些信息 https://github.co ...

  7. Spring Boot 使用 JWT 进行身份和权限验证

    上周写了一个 适合初学者入门 Spring Security With JWT 的 Demo,这篇文章主要是对代码中涉及到的比较重要的知识点的说明. 适合初学者入门 Spring Security W ...

  8. Spring Boot Security JWT 整合实现前后端分离认证示例

    前面两章节我们介绍了 Spring Boot Security 快速入门 和 Spring Boot JWT 快速入门,本章节使用 JWT 和 Spring Boot Security 构件一个前后端 ...

  9. VerificationCodeService

    package me.zhengjie.system.domain; import lombok.AllArgsConstructor; import lombok.Data; import lomb ...

随机推荐

  1. Python的 5 种高级用法,效率提升没毛病!

    任何编程语言的高级特征通常都是通过大量的使用经验才发现的.比如你在编写一个复杂的项目,并在 stackoverflow 上寻找某个问题的答案.然后你突然发现了一个非常优雅的解决方案,它使用了你从不知道 ...

  2. String 字符串,heredoc,nowdoc

    一个字符串可以用 4 种方式表达: 单引号 双引号 heredoc 语法结构 nowdoc 语法结构(自 PHP 5.3.0 起) 单引号 定义一个字符串的最简单的方法是用单引号把它包围起来(字符 ' ...

  3. 实战Arch Unit

    在以前的文章中介绍了通过 [<实战PMD>](https://zhuanlan.zhihu.com/p/105585075).[<实战Checkstyle>](https:// ...

  4. 基于表单的web暴力破解

    暴力破解 概述 连续性尝试+字典+自动化 如果一个网站没有对登录接口实施防暴力破解的措施,或者实施了不合理的措施,则该网站存在暴力破解漏洞. 是否要求用户设置了复杂的密码 是否每次认证都是用安全的验证 ...

  5. PAT Advanced 1086 Tree Traversals Again (25) [树的遍历]

    题目 An inorder binary tree traversal can be implemented in a non-recursive way with a stack. For exam ...

  6. [RoarCTF 2019]Easy Java

    0x01知识点: WEB-INF/web.xml泄露 WEB-INF主要包含一下文件或目录: /WEB-INF/web.xml:Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命 ...

  7. 用Emoji和照片挑战大众点评,YOBO玩转新点评方式能引领潮流吗?

    对于一家企业来说,要想获得长久生命力的必备元素是什么?是技术底蕴和海量资金?但诺基亚.摩托罗拉和黑莓等巨头的崩塌,已经证明再稳固的基础都有可能只是沙子做的.是让人工智能.云计算.大数据等前沿技术赋能于 ...

  8. 并发与高并发(七)-线程安全性-原子性-atomic

    一.线程安全性定义 定义:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程 ...

  9. linux系统终端介绍

    https://zhidao.baidu.com/question/174261014.html

  10. NGINX常用模块(二)

    5.Nginx日志配置 Nginx有非常灵活的日志记录模式.每个级别的配置可以有各自独立的访问日志.日志格式 通过log_format命令定义格式 1.log_format指令 # 配置语法:包括:e ...