Springboot+SpringSecurity+JWT实现登录认证及鉴权

1 篇文章 0 订阅
0 篇文章 0 订阅

因为现在项目重构,在网上找了很多这方面的案例,常用的登录认证和前端鉴权就是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源码下载

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot框架是一个开源的Java框架,为Java开发者提供了一种快速开发的方式。Spring Boot框架具有简单、可靠、高效、强大等优点,它可以快速构建一个高效的Java Web应用程序或微服务。在Spring Boot框架中,我们可以轻松地导出Word表格和文字模板以及程序,具体如下: 1. 导出Word表格 首先,我们可以利用Spring Boot框架中的Apache POI库来导出Word表格。我们只需要创建一个包含表格内容的数据模型,并使用Apache POI库将数据模型中的表格内容输出到Word文档中即可。具体的步骤如下: 1)添加Apache POI库的依赖。 2)创建一个表格数据模型,包含表格结构和内容。 3)创建一个Word文档,并将表格数据输出到Word文档中。 2. 导出文字模板 除了导出Word表格外,我们还可以利用Spring Boot框架中的Thymeleaf模板引擎来导出文字模板。Thymeleaf是一个非常流行的Java模板引擎,它可以让我们以非常简单的方式创建动态模板。 具体的步骤如下: 1)安装Thymeleaf模板引擎。 2)创建一个文字模板,使用Thymeleaf模板引擎生成模板。 3)将生成的模板输出到Web浏览器或保存到本地文件中。 3. 编写程序 最后,我们还需要编写程序来实现导出Word表格和文字模板的功能。具体来说,我们需要编写控制器、服务以及视图层的代码来完成这些功能。 总之,Spring Boot框架提供了一种快速、简单、高效的方式来导出Word表格和文字模板,同时也提供了大量的工具和库来加快开发效率。如果我们熟练掌握了Spring Boot框架的使用方法,那么在开发Java Web应用程序或微服务时就可以更加高效、快速地完成任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值