话不多说,直接搞代码
1.在pom.xml添加依赖
<!-- securityr认证-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<!--json-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>2.在config包新建SecurityConfig.java文件,新建auth包,在auth包里新建以下文件
AuthenticationBean.java
@Data
public class AuthenticationBean {
private String username;
private String password;
}AuthResult.java
public enum AuthResult implements EnumInterface {
SUCCESS(0, "登录成功"),
UNAUTHORIZED(401, "身份验证失败"),
FORBIDDEN(403, "权限验证失败"),
USER_NOT_EXIST(407, "用户不存在"),
USER_PASSWORD_ERR(408, "密码不正确"),
;
private final Integer code;
private final String message;
AuthResult(Integer code, String message) {
this.code = code;
this.message = message;
}
@Override
public Integer getCode() {
return this.code;
}
@Override
public String getMessage() {
return this.message;
}
}
CustomAuthenticationFilter.java
@Slf4j
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
log.info("登录拦截");
//attempt Authentication when Content-Type is json
//use jackson to deserialize json
ObjectMapper mapper = new ObjectMapper();
UsernamePasswordAuthenticationToken authRequest = null;
try (InputStream is = request.getInputStream()) {
AuthenticationBean authenticationBean = mapper.readValue(is, AuthenticationBean.class);
log.info(authenticationBean.toString());
authRequest = new UsernamePasswordAuthenticationToken(
authenticationBean.getUsername(), authenticationBean.getPassword());
} catch (IOException e) {
e.printStackTrace();
new UsernamePasswordAuthenticationToken(
"", "");
} finally {
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
//transmit it to UsernamePasswordAuthenticationFilter
}
}
JwtAccessDeniedHandler.java
@Slf4j
@Component
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
log.info("权限异常处理");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
Map map = new HashMap();
map.put("code", AuthResult.FORBIDDEN.getCode());
map.put("message", AuthResult.FORBIDDEN.getMessage());
String json = JSON.toJSONString(map);
response.setContentType("text/json;charset=utf-8");
response.getWriter().write(json);
}
}JwtAuthenticationEntryPoint.java
@Slf4j
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
log.info("身份验证失败");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
Map map = new HashMap<>();
map.put("code", AuthResult.UNAUTHORIZED.getCode());
map.put("message", AuthResult.UNAUTHORIZED.getMessage());
String json = JSON.toJSONString(map);
response.setContentType("text/json;charset=utf-8");
response.getWriter().write(json);
}JwtAuthenticationTokenFilter.java
@Component
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private UserDetailsService userService;
@Autowired
private JwtToken jwtToken;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String requestUrl = request.getRequestURI();
log.info(requestUrl);
String authToken = request.getHeader("Authorization");
if (authToken != null) {
authToken = authToken.replace("Bearer ", "");
}
log.info(authToken);
String username = jwtToken.getUsernameFromToken(authToken);
log.info("token 验证 {}", username);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userService.loadUserByUsername(username);
if (jwtToken.validateToken(authToken, userDetails)) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
// 将 authentication 存入 ThreadLocal,方便后续获取用户信息
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
filterChain.doFilter(request, response);
}
}
JwtToken.java
@Data
@ConfigurationProperties(prefix = "jwt")
@Component
@Slf4j
public class JwtToken {
// 过期时间 毫秒
private Long expiration;
private String secret;
private String header;
/**
* 从数据声明生成令牌
*
* @param claims 数据声明
* @return 令牌
*/
private String generateToken(Map<String, Object> claims) {
log.info(expiration.toString());
log.info(secret);
Date expirationDate = new Date(System.currentTimeMillis() + expiration);
return Jwts.builder().setClaims(claims).setExpiration(expirationDate).signWith(SignatureAlgorithm.HS256, secret).compact();
}
/**
* 从令牌中获取数据声明
*
* @param token 令牌
* @return 数据声明
*/
public Claims getClaimsFromToken(String token) {
Claims claims;
try {
claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
} catch (Exception e) {
claims = null;
}
return claims;
}
public Date getExpiration(String token) {
Claims claims = this.getClaimsFromToken(token);
Date date = claims.getExpiration();
return date;
}
/**
* 生成令牌
*
* @param userDetails 用户
* @return 令牌
*/
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>(2);
JwtUser jwtUser = (JwtUser) userDetails;
String token = jwtUser.getUsername();
if (jwtUser.getOther() != null) {
token = token + "|" + jwtUser.getOther();
}
claims.put(Claims.SUBJECT, token);
claims.put(Claims.ISSUED_AT, new Date());
return generateToken(claims);
}
/**
* 从令牌中获取用户名
*
* @param token 令牌
* @return 用户名
*/
public String getUsernameFromToken(String token) {
String username;
try {
Claims claims = getClaimsFromToken(token);
username = claims.getSubject();
} catch (Exception e) {
username = null;
}
return username;
}
public String getUserId(String token) {
String username;
try {
Claims claims = getClaimsFromToken(token);
username = claims.getSubject();
} catch (Exception e) {
username = null;
}
return username;
}
/**
* 判断令牌是否过期
*
* @param token 令牌
* @return 是否过期
*/
public Boolean isTokenExpired(String token) {
try {
Claims claims = getClaimsFromToken(token);
Date expiration = claims.getExpiration();
return expiration.before(new Date());
} catch (Exception e) {
return true;
}
}
/**
* 刷新令牌
*
* @param token 原令牌
* @return 新令牌
*/
public String refreshToken(String token) {
String refreshedToken;
try {
Claims claims = getClaimsFromToken(token);
claims.put(Claims.ISSUED_AT, new Date());
refreshedToken = generateToken(claims);
} catch (Exception e) {
refreshedToken = null;
}
return refreshedToken;
}
/**
* 验证令牌
*
* @param token 令牌
* @param userDetails 用户
* @return 是否有效
*/
public Boolean validateToken(String token, UserDetails userDetails) {
String username = getUsernameFromToken(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
}
JwtUser.java
@NoArgsConstructor
@Setter
@Component
public class JwtUser implements UserDetails {
private Integer id;
private String username;
private String password;
private String name;
private String other;
private Integer roleId;
private Collection<? extends GrantedAuthority> authorities;
public String getOther() {
return this.other;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
public Integer getId() {
return id;
}
@Override
public String getUsername() {
return username;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
public Integer getRoleId() {
return roleId;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
LoginFailureHandler.java
@Slf4j
@Component
public class LoginFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
log.info("登录失败");
// 使用fastjson
// 指定响应格式是json
Map map = new HashMap();
if (exception.getClass() == UsernameNotFoundException.class) {
map.put("code", AuthResult.USER_NOT_EXIST.getCode());
map.put("message", AuthResult.USER_NOT_EXIST.getMessage());
} else {
map.put("code", AuthResult.USER_PASSWORD_ERR.getCode());
map.put("message", AuthResult.USER_PASSWORD_ERR.getMessage());
}
String json = JSON.toJSONString(map);
response.setContentType("text/json;charset=utf-8");
response.getWriter().write(json);
}
}
MyAuthenticationSuccessHandler.java
@Slf4j
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Autowired
private JwtToken jwtToken;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
log.info("登录成功");
log.info(authentication.getName());
JwtUser userDetails = (JwtUser) authentication.getPrincipal();
log.info(JSON.toJSONString(userDetails));
String token = jwtToken.generateToken(userDetails);
Claims claims = jwtToken.getClaimsFromToken(token);
Date expiration = claims.getExpiration();
UserSimple userSimple = new UserSimple();
BeanUtils.copyProperties(userDetails, userSimple);
Map tokenMap = new HashMap();
tokenMap.put("token", token);
tokenMap.put("expiration", expiration);
Map result = new HashMap();
Map data = new HashMap();
data.put("user", userSimple);
data.put("token", tokenMap);
result.put("data", data);
result.put("code", AuthResult.SUCCESS.getCode());
result.put("message", "登录成功");
SecurityContextHolder.getContext().setAuthentication(authentication);
String json = JSON.toJSONString(result);
response.setContentType("text/json;charset=utf-8");
response.getWriter().write(json);
}
}
UserDetailsServiceImpl.java
@Service
@Slf4j
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
log.info(username);
userQueryWrapper.eq("username", username);
User user = this.userService.getOne(userQueryWrapper);
if (user == null) {
log.info(String.format("%s.这个用户不存在", username));
throw new UsernameNotFoundException(String.format("%s.这个用户不存在", username));
}
log.info("加载用户信息");
List<Integer> rolesId = new ArrayList<>();
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
JwtUser jwtUser = new JwtUser();
jwtUser.setName(user.getName());
jwtUser.setId(user.getId());
jwtUser.setUsername(user.getUsername());
jwtUser.setPassword(user.getPassword());
jwtUser.setAuthorities(grantedAuthorities);
return jwtUser;
}
}
UserSimple.java
@Data
public class UserSimple {
private Integer id;
private String username;
private String name;
}
文件目录如下

3.在SwaggerConfig.java类中加入Security授权信息
SwaggerConfig.java
/**
* <p>
*
* </p>
*
* @author Qin Xiaotian
* @since 2021-8-4
*/
@Component
@ConfigurationProperties("swagger")
@Data
public class SwaggerConfig {
private final SwaggerProperties swaggerProperties;
public SwaggerConfig(SwaggerProperties swaggerProperties) {
this.swaggerProperties = swaggerProperties;
}
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.OAS_30).pathMapping("/")
// 定义是否开启swagger,false为关闭,可以通过变量控制
.enable(swaggerProperties.getEnable())
// 将api的元信息设置为包含在json ResourceListing响应中。
.apiInfo(apiInfo())
// 接口调试地址
.host(swaggerProperties.getTryHost())
// 选择哪些接口作为swagger的doc发布
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
// 支持的通讯协议集合
.protocols(newHashSet("https", "http"))
// 授权信息设置,必要的header token等认证信息
.securitySchemes(securitySchemes())
// 授权信息全局应用
.securityContexts(securityContexts());
}
/**
* API 页面上半部分展示信息
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title(swaggerProperties.getApplicationName() + " Api Doc")
.description(swaggerProperties.getApplicationDescription())
.version("Application Version: " + swaggerProperties.getApplicationVersion() + ", Spring Boot Version: " + SpringBootVersion.getVersion())
.build();
}
/**
* 设置授权信息
*/
private List<SecurityScheme> securitySchemes() {
ApiKey apiKey = new ApiKey("Authorization", "Authorization", In.HEADER.toValue());
return Collections.singletonList(apiKey);
}
/**
* 授权信息全局应用
*/
private List<SecurityContext> securityContexts() {
return Collections.singletonList(
SecurityContext.builder()
.securityReferences(Collections.singletonList(new SecurityReference("Authorization", new AuthorizationScope[]{new AuthorizationScope("global", "")})))
.build()
);
}
@SafeVarargs
private final <T> Set<T> newHashSet(T... ts) {
if (ts.length > 0) {
return new LinkedHashSet<>(Arrays.asList(ts));
}
return null;
}
}4.测试
运行springBoot项目,在右上角多了一个Authorize (授权)按钮

直接访问接口,如果没有经过登录授权,是无法访问
通过PostMan登录获取 token,然后使用生成的token信息进行登录授权


授权之后,就可以访问所有接口信息(注:每次刷新页面,需要重新授权
版权声明:本文为qq_28503457原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。