感觉现在的Java
开发人员已经离不开Spring
框架,不讨论这种事情是好是坏,但是确实好用,但是个人入门有些东西难度还是很高的,摸索的进度有些许的慢,只能慢慢的更新了,那今天就慢慢更新一期SpringSecurity
的入门篇,完成完整的系统,可以直接投入生产开发使用。
Java
基础,会Spring Boot
、Spring Security
、MyBatis plus
token
token
有什么样的作用先来体验一下什么是 token
package com.shaojie.authority.jwt;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.IdUtil;
import com.shaojie.authority.exception.TokenException;
import com.shaojie.authority.service.impl.AuthorityServiceImpl;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import java.sql.Date;
/**
* @author: ShaoJie
* @data: 2020年02月22日 18:17
* @Description: jwt 生成校验 token
*/
@Slf4j
@Configuration
public class JwtUtil {
/**
* 认证关键key
*/
String signingKey = "SigningKey";
/**
* 创建生成 token
*
* @return
*/
public String createToken() {
//30秒过期
long now = System.currentTimeMillis();
long exp = now + 1000 * 60;
// builder 构建 token
String token = Jwts.builder()
// 设置唯一的 id
.setId(IdUtil.simpleUUID())
// 设置主题
.setSubject("token")
// 设置角色
.claim("authorities", "admin")
// 设置角色集
// .addClaims()
// 设置过期时间
.setExpiration(new Date(exp))
// 设置 token 签发的时间
.setIssuedAt(new DateTime())
// 设置签名 使用HS256算法,并设置SecretKey(字符串) 签名算法和秘钥
.signWith(SignatureAlgorithm.HS256, signingKey)
// 以下内容构建JWT并将其序列化为紧凑的,URL安全的字符串
.compact();
log.info("token:{}", token);
return token;
}
/**
* 解析 token
*
* @param token 用户的 token
*/
public void parseToken(String token) throws TokenException {
Claims claims = Jwts.parser().setSigningKey(signingKey).parseClaimsJws(token).getBody();
if (claims.equals(null))
throw new TokenException();
log.info("解析的数据:{}", claims);
}
public static void main(String[] args) {
JwtUtil jwtUtil = new JwtUtil();
String token = jwtUtil.createToken();
try {
jwtUtil.parseToken(token);
} catch (TokenException e) {
log.info("token 过期");
}
System.out.println(token);
}
}
生成的token:
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJiZmNjYzRlOWQ5OWY0Mzc3YTI1MjBmNjkxZDM1NzkyMiIsInN1YiI6InRva2VuIiwiYWRtaW4iOiJTaGFvSmllIiwiZXhwIjoxNTk1NDA0MTU4LCJpYXQiOjE1OTU0MDQwOTh9.AjPDjf40BnAzgnU3mCpjMI8KYggEVR8264JATKg4cFc
解析到的token:
{jti=bfccc4e9d99f4377a2520f691d357922, sub=token, admin=ShaoJie, exp=1595404158, iat=1595404098}
解析创建的token
不难发现其中包含的信息:当前的创建token
的主题、角色、过期时间等
这只是学习运用的第一步,体验这种认证带来的方便,和便捷。然后进入到正题,开始更新这样的一期Spring Boot
整合SpringSecurity
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>top.lzmvlog</groupId>
<artifactId>authority</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>authority</name>
<description>Spring Boot 整合 JWT 做授权认证</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR4</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.22</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.6</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package top.lzmvlog.authority.util.jwt;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpStatus;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import top.lzmvlog.authority.exception.TokenException;
import top.lzmvlog.authority.util.date.DateUtil;
/**
* @author ShaoJie
* @Date 2020年05月12 15:16
* @Description: 生成解析 token 的工具类
*/
@Component
@Slf4j
public class JwtUtil {
/**
* 签名密钥
*/
@Value("${auth.token.signingKey}")
private String signingKey;
/**
* 创建生成 token
*
* @return String 生成的 token
*/
public String createToken(String account) {
log.info("账号:{} 登录成功", account);
return Jwts.builder()
// 设置唯一的 ida
.setId(IdUtil.simpleUUID())
// 设置主要包含的信息
.setSubject(account)
// 设置过期时间
.setExpiration(new DateUtil().getNowDateOneTime())
// 设置 token 签发的时间
.setIssuedAt(new DateTime())
// 设置签名 使用HS256算法,并设置SecretKey(字符串) 签名算法和秘钥
.signWith(SignatureAlgorithm.HS256, signingKey)
// 以下内容构建JWT并将其序列化为紧凑的,URL安全的字符串
.compact();
}
/**
* 解析当前的 token
*
* @param token token 信息
* @return String token种解析到的信息
*/
public String parseToken(String token) {
Claims claims = Jwts.parser().setSigningKey(signingKey).parseClaimsJws(token).getBody();
if (claims.equals(null))
throw new TokenException(HttpStatus.HTTP_INTERNAL_ERROR, "token 信息错误 重新授权");
return claims.getSubject();
}
}
当前的JwtUtil
并没有加入关于角色的任何信息,只是单纯的针对账号去授权,生成这样的一个token
,当然你也可以将你的权限信息去进行授权,自行发散思维。
package top.lzmvlog.authority.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import top.lzmvlog.authority.filter.JwtAuthenticationFilter;
import top.lzmvlog.authority.handler.JwtAccessDeniedHandler;
/**
* @author ShaoJie
* @Date 2020年05月12 14:36
* @Description: 安全验证配置
*/
@Configuration
@EnableWebSecurity
public class SecurityVerificationConfiguration extends WebSecurityConfigurerAdapter {
/**
* 密码加密
*
* @return
*/
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 拦截器
*/
@Autowired
public JwtAuthenticationFilter jwtAuthenticationFilter;
/**
* jwt 验证处理器
*/
@Autowired
public JwtAccessDeniedHandler jwtAccessDeniedHandler;
/**
* toekn 配置
*/
@Autowired
public TokenConfiguration tokenConfiguration;
/**
* 授权 、 验证
*
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
// 授权地址不需要验证
.antMatchers("/auth/token").permitAll()
// 用户注册地址
.antMatchers("/user/registered").permitAll()
// 其余的都需要校验
.anyRequest().authenticated()
.and()
// 添加后置处理拦截器
.addFilterAfter(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
// 访问拒绝处理程序
.accessDeniedHandler(jwtAccessDeniedHandler)
.and()
.apply(tokenConfiguration)
.and()
// 取消 session 的状态
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable();
}
}
BCryptPasswordEncoder
官方提供的密码加密类,对注册的用户信息进行加密,例如用户的登录密码。
JwtAuthenticationFilter
权限拦截器,用于拦截用户信息,进行权限校验。
JwtAccessDeniedHandler
拒绝访问处理器。
TokenConfiguration
适配器配置,用于修改默认的认证处理器,实现自定义的验证
下次更新将着重对这些类细谈其实现,尝鲜体验可访问我的 GitHub 查看 authority
项目 clone
$ git clone https://github.com/lzmvlog/authority.git