因为现在项目重构,在网上找了很多这方面的案例,常用的登录认证和前端鉴权就是SpringSecurity+JWT来实现。所以在网上搜了一些案例,集成到自己的项目中,做了适应项目的修改及调整,分享demo出来给有需要的码友。
备注:其实在项目中一般都只会用到登录认证,至于鉴权,Security实际上就是将所有权限的角色遍历,和当前登录用户的角色匹配是否具有权限,每次请求都会遍历,过于繁琐,在实际项目中一般很少使用。
1.首先引入pom.xml依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--security-->
<!--jwt-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!--jwt-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
2.配置application.properties
server.port=8102
spring.datasource.url=jdbc:mysql://localhost:3306/business?useSSL=false
spring.datasource.username=business
spring.datasource.password=123456
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
3.Spring-Security配置类(重要):
package com.business.securityjwtdemo.config;
import com.business.securityjwtdemo.exception.JWTAccessDeniedHandler;
import com.business.securityjwtdemo.exception.JWTAuthenticationEntryPoint;
import com.business.securityjwtdemo.filter.JWTAuthenticationFilter;
import com.business.securityjwtdemo.filter.JWTAuthorizationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
/**
* Spring-Security配置类(需要继承WebSecurityConfigurerAdapter) - 项目启动执行
*
* @author Tom
* @date 2020-08-14
*
* 注释:
* 注解@EnableWebSecurity开启Security功能
* 注解@EnableGlobalMethodSecurity(prePostEnabled = true),Security默认是禁用注解的,要想开启注解需要此配置,其表达式时间方法级别的安全性4个注解:(
* @PreAuthorize 在方法调用之前,基于表达式的计算结果来限制对方法的访问
* @PostAuthorize 允许方法调用,但是如果表达式计算结果为false,将抛出一个安全性异常
* @PostFilter 允许方法调用,但必须按照表达式来过滤方法的结果
* @PreFilter 允许方法调用,但必须在进入方法之前过滤输入值 )例如:@PreAuthorize("hasRole('ADMIN')")表示用户具有admin角色,才能访问该方法
*/
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* UserDetailsService的实现类实在太多,这里设置一下我们要注入的实现类(@Qualifier("userDetailsServiceImpl"))
*
* UserDetailsServiceImpl中我们重写了loadUserByUsername方法,其中的校验(用户名,密码)为我们自定义查询
*/
@Autowired
@Qualifier("userDetailsServiceImpl")
private UserDetailsService userDetailsService;
/**
* 对密码进行加密的类,配置在spring中,方便调用
* 例如:bCryptPasswordEncoder.encode(registerUser.get("password"))
* @return
*/
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
/**
* 重写configure方法,根据项目需求配置,并将将写好的相应配置类引入
*
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
/**cors()开启跨域*/
http.cors()
.and()
/**禁用CSRF保护*/
.csrf().disable()
/**http.authorizeRequests()方法添加多个子项(.antMatchers(****))来指定URL的自定义要求*/
.authorizeRequests()
// 例子: /tasks/**请求路径下的DELETE请求需要"ADMIN"权限才能操作
// .antMatchers(HttpMethod.DELETE, "/tasks/**").hasRole("ADMIN")
// 测试用资源,需要验证了的用户才能访问
// .antMatchers("/tasks/**").authenticated()
/**对http所有的请求必须通过授权认证才可以访问*/
.anyRequest().authenticated()
/**其他都放行了*/
// .anyRequest().permitAll()
.and()
/**添加自定义的登录拦截方式(JWTAuthenticationFilter配置类) 注意:顺序:JWTAuthenticationFilter必须在JWTAuthorizationFilter之前*/
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
/**添加自定义的请求拦截方式(JWTAuthorizationFilter配置类)*/
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
/**不需要session*/
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
/**自定义异常处理(没有携带token或者token无效,JWTAuthenticationEntryPoint类配置处理)*/
.exceptionHandling().authenticationEntryPoint(new JWTAuthenticationEntryPoint())
/**添加无权限时的处理(JWTAccessDeniedHandler类配置无访问权限异常处理)*/
.accessDeniedHandler(new JWTAccessDeniedHandler());
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
}
4.JWTAuthenticationFilter类,继承于UsernamePasswordAuthenticationFilter(登录拦截器,校验成功后返回一个token给客户端)
package com.business.securityjwtdemo.filter;
import com.business.securityjwtdemo.entity.JwtUser;
import com.business.securityjwtdemo.model.LoginUser;
import com.business.securityjwtdemo.utils.JwtTokenUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* 登录拦截器 - 请求登录接口/auth/login时会被拦截
*
* 调用attemptAuthentication方法获取登录请求的(用户名,密码,记住我)等信息,
* 调用authenticationManager.authenticate()让spring-security去进行验证
* JWTAuthenticationFilter继承于UsernamePasswordAuthenticationFilter
* 该拦截器用于获取用户登录的信息,只需创建一个token并调用authenticationManager.authenticate()让spring-security去进行验证就可以了,
* 不用自己查数据库再对比密码了,这一步交给spring去操作。 这个操作有点像是shiro的subject.login(new UsernamePasswordToken()),
* 验证的事情交给框架。
*
* @author Tom
* @date 2020-08-14
*/
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
/**
* 并发情况的安全线程 - 为每个用户配置唯一的登录持久化状态
*/
private ThreadLocal<Integer> rememberMe = new ThreadLocal<>();
private AuthenticationManager authenticationManager;
/**
* 自定义登录URL(使用Security默认的登录地址为/login) - 根据项目需求配置
* @param authenticationManager
*/
public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
super.setFilterProcessesUrl("/auth/login");
}
/**
* 第一步:获取用户参数,并进行校验(用户名密码)
* @param request
* @param response
* @return
* @throws AuthenticationException
*/
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
/**从输入流中获取到登录的信息*/
LoginUser loginUser = new ObjectMapper().readValue(request.getInputStream(), LoginUser.class);
rememberMe.set(loginUser.getRememberMe() == null ? 0 : loginUser.getRememberMe());
return authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginUser.getUserName(), loginUser.getPassWord(), new ArrayList<>())
);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* 第二步:第一步方法成功验证后,则生成token并返回
* @param request
* @param response
* @param chain
* @param authResult
* @throws IOException
* @throws ServletException
*/
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
/**获取上一步验证后的JwtUser对象*/
JwtUser jwtUser = (JwtUser) authResult.getPrincipal();
boolean isRemember = rememberMe.get() == 1;
List<String> role = new ArrayList<>();
Collection<? extends GrantedAuthority> authorities = jwtUser.getAuthorities();
if(authorities != null && authorities.size() > 0){
for (GrantedAuthority authority : authorities){
role.add(authority.getAuthority());
}
}
/**根据jwtUser信息该创建一个token*/
String token = JwtTokenUtils.createToken(jwtUser.getUsername(), role, isRemember);
/**
* 1.返回创建成功的token
* 2.按照jwt的规定,最后请求的时候应该是 "Bearer token"
* 3.返回token加上"Bearer "前缀
*/
response.setHeader("token", JwtTokenUtils.TOKEN_PREFIX + token);
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
response.getWriter().write("authentication failed, reason: " + failed.getMessage());
}
}
5.JWTAuthorizationFilter类,继承于BasicAuthenticationFilter(过滤器 - 处理所有HTTP请求,并检查是否存在带有正确令牌的Authorization标头,认证成功才能请求相应接口)
package com.business.securityjwtdemo.filter;
import com.business.securityjwtdemo.exception.TokenIsExpiredException;
import com.business.securityjwtdemo.utils.JwtTokenUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* 过滤器 - 处理所有HTTP请求,并检查是否存在带有正确令牌的Authorization标头
*
* @author Tom
* @date 2020-08-14
*/
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
public JWTAuthorizationFilter(AuthenticationManager authenticationManager) {
super(authenticationManager);
}
/**
* 过滤器拦截方法
* @param request
* @param response
* @param chain
* @throws IOException
* @throws ServletException
*/
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
/**
* 获取请求头中的token
*/
String tokenHeader = request.getHeader(JwtTokenUtils.TOKEN_HEADER);
/**如果请求头中没有Authorization信息则直接执行放行(或者请求头中没有TOKEN_PREFIX前缀)*/
if (tokenHeader == null || !tokenHeader.startsWith(JwtTokenUtils.TOKEN_PREFIX)) {
chain.doFilter(request, response);
return;
}
try {
/**如果请求头中有token,则进行解析,并且设置认证信息*/
SecurityContextHolder.getContext().setAuthentication(getAuthentication(tokenHeader));
} catch (TokenIsExpiredException e) {
/**返回json形式的错误信息*/
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
String reason = "统一处理,原因:" + e.getMessage();
response.getWriter().write(new ObjectMapper().writeValueAsString(reason));
response.getWriter().flush();
return;
}
super.doFilterInternal(request, response, chain);
}
/**
* 将token进行解析,获取用户信息,并且设置认证信息(对Token进行校验)
* @param tokenHeader
* @return
* @throws TokenIsExpiredException
*/
private UsernamePasswordAuthenticationToken getAuthentication(String tokenHeader) throws TokenIsExpiredException {
String token = tokenHeader.replace(JwtTokenUtils.TOKEN_PREFIX, "");
boolean expiration = JwtTokenUtils.isExpiration(token);
if (expiration) {
throw new TokenIsExpiredException("token超时了");
} else {
String username = JwtTokenUtils.getUserName(token);
List<String> roles = JwtTokenUtils.getUserRole(token);
if (username != null) {
List<GrantedAuthority> list = new ArrayList<>();
if(roles != null && roles.size() > 0){
for (String role : roles) {
list.add(new SimpleGrantedAuthority(role));
}
}
return new UsernamePasswordAuthenticationToken(username, null, list);
}
}
return null;
}
}
6.三个异常配置类:
一.没有访问权限
package com.business.securityjwtdemo.exception;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Description:没有访问权限
*
* @author: Tom
* @date: 2020-08-14
*/
public class JWTAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setContentType("application/json; charset=utf-8");
httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
String reason = "统一处理,原因(没有访问权限):" + e.getMessage();
httpServletResponse.getWriter().write(new ObjectMapper().writeValueAsString(reason));
}
}
二.没有携带token或者token无效
package com.business.securityjwtdemo.exception;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Description:没有携带token或者token无效
*
* @author Tom
* @date 2020-08-14
*/
public class JWTAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
String reason = "统一处理,原因(无token或token无效):" + authException.getMessage();
response.getWriter().write(new ObjectMapper().writeValueAsString(reason));
}
}
三.Token自定义异常
package com.business.securityjwtdemo.exception;
/**
* @Description: Token自定义异常
*
* @author: Tom
* @date: 2020-08-14
*/
public class TokenIsExpiredException extends Exception {
public TokenIsExpiredException() {}
public TokenIsExpiredException(String message) {
super(message);
}
public TokenIsExpiredException(String message, Throwable cause) {
super(message, cause);
}
public TokenIsExpiredException(Throwable cause) {
super(cause);
}
public TokenIsExpiredException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
7.UserDetailsServiceImpl类,实现了UserDetailsService(Spring-Security自定义身份认证类(实现UserDetailsService并重写loadUserByUsername方法),在重写方法中主要是通过查询用户信息交给Security去匹配)
package com.business.securityjwtdemo.service;
import com.business.securityjwtdemo.entity.JwtUser;
import com.business.securityjwtdemo.entity.User;
import com.business.securityjwtdemo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.HashSet;
import java.util.Set;
/**
* Spring-Security自定义身份认证类(实现UserDetailsService并重写loadUserByUsername方法)
* 在loadUserByUsername方法内校验用户名密码是否正确并返回一个UserDetails对象
*
* @author Tom
* @date 2020-08-14
*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
/**
* 因为JwtUser实现了UserDetails,所以返回一个封装了User信息的JwtUser
* @param name 用户名
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
User user = userRepository.findByUserName(name);
/**正常业务逻辑是User对象中封装了Role集合,此处手动添加供调试用*/
Set<String> roles = new HashSet<>();
roles.add("ROLE_TEST1");
roles.add("ROLE_TEST2");
roles.add("ROLE_TEST3");
user.setRoles(roles);
/**正常业务逻辑是User对象中封装了Role集合,此处手动添加供调试用*/
return new JwtUser(user);
}
}
8.Jwt的Token工具类
package com.business.securityjwtdemo.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
/**
* Jwt的Token工具类
*
* @author Tom
* @date 2020-08-14
*/
public class JwtTokenUtils {
/**
* 用户请求头中的Token的key(例:Authorization: *************)
*/
public static final String TOKEN_HEADER = "Authorization";
/**
* 返回的Token前缀信息(自定义配置)
*/
public static final String TOKEN_PREFIX = "Bearer ";
/**
* JTW的加密算法SigningKey
*/
private static final String SECRET = "jwtSecret";
/**
* 该JWT的签发者,是否使用是可选的(可以使用项目名称或者作者名称之类)
*/
private static final String ISS = "authTom";
/**
* 角色的key
*/
private static final String ROLE_CLAIMS = "rol";
/**
* 过期时间是3600秒,既是1个小时
*/
private static final long EXPIRATION = 3600L;
/**
* 选择了记住我之后的过期时间为7天
*/
private static final long EXPIRATION_REMEMBER = 604800L;
/**
* 创建token方法
* @param username 用户名
* @param role 角色权限集合
* @param isRememberMe 记住我(是,否) - 记住过期时间为7天,没选择则过期时间为1个小时
* @return
*/
public static String createToken(String username, List<String> role, boolean isRememberMe) {
long expiration = isRememberMe ? EXPIRATION_REMEMBER : EXPIRATION;
HashMap<String, Object> map = new HashMap<>();
map.put(ROLE_CLAIMS, role);
return Jwts.builder()
.signWith(SignatureAlgorithm.HS512, SECRET)
.setClaims(map)
.setIssuer(ISS)
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + expiration * 1000))
.compact();
}
/**
* 从token中获取用户名
* @param token
* @return
*/
public static String getUserName(String token){
return getTokenBody(token).getSubject();
}
/**
* 从token中获取用户角色集合
* @param token
* @return
*/
public static List<String> getUserRole(String token){
return (List<String>) getTokenBody(token).get(ROLE_CLAIMS);
}
/**
* 判断是否已过期
* @param token
* @return
*/
public static boolean isExpiration(String token) {
try {
return getTokenBody(token).getExpiration().before(new Date());
} catch (ExpiredJwtException e) {
return true;
}
}
/**
* 获取token请求体内容
* @param token
* @return
*/
private static Claims getTokenBody(String token){
return Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token)
.getBody();
}
}
9.含有用户信息的JWTUser对象,继承UserDetails类
package com.business.securityjwtdemo.entity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* 含有用户信息的JWTUser对象,用于从Token中取出user信息
*
* @author Tom
* @date 2020-08-14
*/
public class JwtUser implements UserDetails {
/**
* 用户ID
*/
private Integer id;
/**
* 用户名
*/
private String userName;
/**
* 密码
*/
private String passWord;
/**
* 权限信息
*/
private Collection<? extends GrantedAuthority> authorities;
/**
* 无参构造器
*/
public JwtUser() {}
/**
* 使用user创建jwtUser的构造器
* @param user 用户对象
*/
public JwtUser(User user) {
id = user.getId();
userName = user.getUserName();
passWord = user.getPassWord();
if(user.getRoles() != null && user.getRoles().size() > 0){
List<GrantedAuthority> list = new ArrayList<>();
for (String role : user.getRoles()) {
list.add(new SimpleGrantedAuthority(role));
}
authorities = list;
}
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return passWord;
}
@Override
public String getUsername() {
return userName;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public String toString() {
return "JwtUser{" +
"id=" + id +
", userName='" + userName + '\'' +
", passWord='" + passWord + '\'' +
", authorities=" + authorities +
'}';
}
}
11.我们的User类,数据库中对应的user表
package com.business.securityjwtdemo.entity;
import javax.persistence.*;
import java.util.Set;
/**
* User类
*
*/
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column(name = "userName")
private String userName;
@Column(name = "passWord")
private String passWord;
@Transient
private Set<String> roles;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
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 Set<String> getRoles() {
return roles;
}
public void setRoles(Set<String> roles) {
this.roles = roles;
}
}
12.这里使用hibernate作为dao层
package com.business.securityjwtdemo.repository;
import com.business.securityjwtdemo.entity.User;
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<User, Integer> {
User findByUserName(String userName);
}
13.给个登录请求的封装对象:
package com.business.securityjwtdemo.model;
/**
* 登录用户请求参数对象
*
* @author Tom
* @date 2020-08-14
*/
public class LoginUser {
/**
* 用户名
*/
private String userName;
/**
* 密码
*/
private String passWord;
/**
* 是否记住我
*/
private Integer rememberMe;
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 Integer getRememberMe() {
return rememberMe;
}
public void setRememberMe(Integer rememberMe) {
this.rememberMe = rememberMe;
}
}
到此,准备工作完成了,可以写接口调用测试了。
可以使用postman进行登录测试:
可以看到登录成功,返回一个Token.
写了接口用来调用测试:
package com.business.securityjwtdemo.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
/**
* 测试请求
*/
@RestController
@RequestMapping("/tasks")
public class TaskController {
@GetMapping
public String listTasks(){
return "任务列表";
}
}
使用postman,带上token请求:
到此登录认证成功。
附上demo源码:demo源码下载