SpringSecurity集成JWT

原创
2019/09/15 14:48
阅读数 241

SpringSecurity集成JWT

JWT简介

JWT是JSON Web Token的缩写,是一种开放的标准,JWT定义了一种紧凑且自包含的标准,该标准旨在将各个主体的信息标准包装JSON对象。主体信息是通过数字签名进行加密和验证的。常使用HMAC算法或者RSA(公钥/私钥的非堆成加密算法)算法对JWT进行签名,安全性很高。

结构

JWT分为三段式, xxxx.yyyyyyyyy.zzzzz

通常包含三个部分
1:Header

{
	"algorithm":"RSA",//表明是哪种算法, RSA或者 SHA256 或者 HMAC
	"type":"JWT" //令牌类型
}

2:Payload

//包含了用户信息, Claim等,有三种类型,公开,保留,私人
{
	"id":"879c21cc040a4fbe23729cee4628568e",
	"name":"Calvin",
	"age":"18",
	"gender":"1",
	"isAdmin":"1"
}

3:Signature

/**
 * 生成一个JWT
 *@param header 头部信息
 *@param payload 主体
 */
public String encriptJWT(Object header, Object payload, String secret){
	encript(Base64.encode(header) + "." + Base64.encode(payload), secret);
}

编码

pom.xml

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.1.7.RELEASE</version>
	<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.calvin.boot</groupId>
<artifactId>boot-security-jwt</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>boot-security-jwt</name>
<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>
 	<!-- jwt -->
 	<dependency>
 		<groupId>org.springframework.security</groupId>
 		<artifactId>spring-security-jwt</artifactId>
 		<version>1.0.9.RELEASE</version>
 	</dependency>
 	<dependency>
 		<groupId>io.jsonwebtoken</groupId>
 		<artifactId>jjwt</artifactId>
 		<version>0.9.1</version>
 	</dependency>
<!--        mybatis-->
	<dependency>
		<groupId>com.baomidou</groupId>
		<artifactId>mybatis-plus-boot-starter</artifactId>
		<version>3.2.0</version>
	</dependency>
	<dependency>
		<groupId>org.mybatis.spring.boot</groupId>
		<artifactId>mybatis-spring-boot-starter</artifactId>
		<version>2.1.0</version>
	</dependency>
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<scope>runtime</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>com.alibaba</groupId>
		<artifactId>fastjson</artifactId>
		<version>1.2.58</version>
	</dependency>
	<dependency>
		<groupId>commons-beanutils</groupId>
		<artifactId>commons-beanutils</artifactId>
		<version>1.9.3</version>
	</dependency>
	<dependency>
		<groupId>commons-logging</groupId>
		<artifactId>commons-logging</artifactId>
		<version>1.2</version>
	</dependency>
</dependencies>

application.yml


server:
  port: 8080

spring:
  application:
    name: boot-security-jwt

  datasource:
    url: jdbc:mysql://localhost:3306/security_jwt?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useAffectedRows=true&useSSL=false&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456


jwt:
  expiration: 7200000
  secret: calvin
  token: Authorization

先写几个比较基础的类 SysUser 继承 UserDetails,重写几个关键方法,其中getAuthorities方法被我改动,注意泛型

import org.springframework.security.core.userdetails.UserDetails;
/**
 * <p> 系统级用户</p>
 *
 * @author Calvin
 * @date 2019/09/06
 * @since
 */
public class SysUser implements UserDetails {


    /**
     * ID
     */
    private String id;

    /**
     * 头像
     */
    private String headImg;

    /**
     * 性别
     */
    private Integer gender;

    /**
     * 年龄
     */
    private Integer age;

    /**
     * 用户名
     */
    private String username;

    /**
     * 密码
     */
    private String password;

    /**
     * 账户
     */
    private String account;

    /**
     * 权限列表
     */
    @TableField(exist = false)
    private List<SysRole> roleList;

    /**
     * 创建时间
     */
    private Date createTime;


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getHeadImg() {
        return headImg;
    }

    public void setHeadImg(String headImg) {
        this.headImg = headImg;
    }

    public Integer getGender() {
        return gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }


    public void setRoleList(List<SysRole> roleList) {
        this.roleList = roleList;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    @Override
    public List<SysRole> getAuthorities() {
        return roleList;
    }

    @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() {
        final StringBuffer sb = new StringBuffer("SysUser{");
        sb.append("id='").append(id).append('\'');
        sb.append(", headImg='").append(headImg).append('\'');
        sb.append(", gender=").append(gender);
        sb.append(", age=").append(age);
        sb.append(", username='").append(username).append('\'');
        sb.append(", password='").append(password).append('\'');
        sb.append(", account='").append(account).append('\'');
        sb.append(", roleList=").append(roleList);
        sb.append(", createTime=").append(createTime);
        sb.append('}');
        return sb.toString();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        SysUser sysUser = (SysUser) o;
        return Objects.equals(id, sysUser.id) &&
                Objects.equals(headImg, sysUser.headImg) &&
                Objects.equals(gender, sysUser.gender) &&
                Objects.equals(age, sysUser.age) &&
                Objects.equals(username, sysUser.username) &&
                Objects.equals(password, sysUser.password) &&
                Objects.equals(account, sysUser.account) &&
                Objects.equals(roleList, sysUser.roleList) &&
                Objects.equals(createTime, sysUser.createTime);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, headImg, gender, age, username, password, account, roleList, createTime);
    }

}

SysRole类继承GrantedAuthority,重写getAuthority方法

import org.springframework.security.core.GrantedAuthority;

/**
 * <p> 简单用户权限类 </p>
 *
 * @author Calvin
 * @see com.calvin.boot.sys.service.SysUserDetailService
 * @see SysUser
 * @date 2019/09/06
 * @since
 */
public class SysRole implements GrantedAuthority {

    private static final long serialVersionUID = -7511279890897762933L;
    /**
     * id
     */
    private String id;

    /**
     * 角色名称
     */
    private String authority;


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public void setAuthority(String authority) {
        this.authority = authority;
    }

    @Override
    public String getAuthority() {
        return authority;
    }

}

相关sql

# 创建数据库
create database security_jwt;
use security_jwt;

# 创建用户表
drop table if exists sys_user;
create table sys_user (
    id varchar(40) primary key ,
    username varchar(20),
    password varchar(32),
    age int ,
    account varchar(50),
    head_img varchar(255),
    gender int,
    create_time datetime
);

# 创建权限表
create table sys_role (
    id varchar(40) primary key ,
    authority varchar(40)
);

# 用户权限映射表
create table sys_user_role(
    id varchar(40) primary key ,
    user_id varchar(40),
    role_id varchar(40),
    delete_flag int(1)
);


# 用户记录
insert into sys_user(id, head_img, gender,age,username, password, account,create_time)
values('1',null,1,20,'admin','e10adc3949ba59abbe56e057f20f883e', 'admin@account.com',now());

# 权限记录
insert into sys_role values ('1','ROLE_USER');
insert into sys_role values ('2','ROLE_ADMIN');
insert into sys_role values ('3','ROLE_GUEST');

# 插入映射关系
insert into sys_user_role values('1','1','1','0');

SysUserMapper && SysRoleMapper

/**
 * <p> 用户的Mapper</p>
 *
 * @author Calvin
 * @date 2019/09/06
 * @see com.calvin.boot.service.impl.SysUserServiceImpl
 * @since
 */
@Mapper
public interface ISysUserMapper extends BaseMapper<SysUser> {

}

------------------------------------------------------------------------

package com.calvin.boot.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.calvin.boot.entity.SysRole;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * <p> 角色Mapper </p>
 *
 * @author Calvin
 * @date 2019/09/06
 * @since
 */
@Mapper
public interface ISysRoleMapper extends BaseMapper<SysRole> {


    /**
     * 多表联查,用户权限
     * @param userId
     * @return
     */
    @Select("select a.id, a.authority from sys_role a join sys_user_role b on a.id = b.role_id where b.user_id = ${userId}")
    List<SysRole> selectByUserId(@Param("userId") String userId);

}

以下是核心,请重点关注

LoginController

/**
 * <p>
 *     登录相关的controller
 * </p>
 * @author Calvin
 */
@RestController
@RequestMapping("/login")
public class LoginController {

    @Autowired
    private JwtTokenUtils jwtTokenUtils;

    @Autowired
    private AuthenticationManager myAuthenticationManager;

    /**
     * 登录接口
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("/userLogin")
    public MessageEntity userLogin(String username, String password){
        UsernamePasswordAuthenticationToken token =
                new UsernamePasswordAuthenticationToken(username, password);
        Authentication authenticate = myAuthenticationManager.authenticate(token);
        SysUser sysUser = (SysUser) authenticate.getPrincipal();
        String jwtToken = jwtTokenUtils.generateToken(sysUser);
        MessageEntity messageEntity = new MessageEntity();
        messageEntity.setCode(200);
        messageEntity.setMsg("success");
        messageEntity.setData(jwtToken);
        return messageEntity;
    }

    /**
     * 重新登录消息
     * @return
     */
    @RequestMapping("/message")
    public MessageEntity loginMessage(){
        MessageEntity messageEntity = new MessageEntity();
        messageEntity.setCode(MessageCode.CREDENTIAL_EXPIRED);
        messageEntity.setData(null);
        messageEntity.setMsg("you need login!");
        return messageEntity;
    }
}

SysUserDetailService 核心类之一

/**
 * <p>UserDetailsService实现, Security核心类之一 </p>
 *
 * @author Calvin
 * @date 2019/09/06
 * @since
 */
@Service
public class SysUserDetailService implements UserDetailsService {


    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private ISysRoleService sysRoleService;

    private static final Logger log = LoggerFactory.getLogger(SysUserDetailService.class);


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SysUser byUsername = sysUserService.findByUsername(username);
        if(byUsername == null){
            log.warn("not found username for : {}", username);
            throw new UsernameNotFoundException("不存在的账户");
        }
        List<SysRole> roles = sysRoleService.listByUserId(byUsername.getId());
        byUsername.setRoleList(roles);
        return byUsername;
    }
}

ISysUserService

/**
 * <p> 用户相关的Service</p>
 *
 * @author Calvin
 * @date 2019/09/06
 * @since
 */
public interface ISysUserService{


    /**
     * 根据用户名查找
     * @param username
     * @return
     */
    SysUser findByUsername(String username);

}

ISysRoleService

/**
 * <p>
 *     角色相关的Service
 * </p>
 *
 * @author Calvin
 * @date 2019/09/06
 * @since
 */
public interface ISysRoleService {


    /**
     * 根据用户名查询到所有角色
     * @param userId
     * @return
     */
    List<SysRole> listByUserId(String userId);
}

JwtTokenUtils

package com.calvin.boot.sys.tools;

import com.calvin.boot.entity.SysUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Clock;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.DefaultClaims;
import io.jsonwebtoken.impl.DefaultClock;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.Map;

/**
 * <p> JwtToken生成器</p>
 *
 * @author Calvin
 * @date 2019/09/06
 * @since
 */
@Component
public class JwtTokenUtils implements Serializable {


    private static final long serialVersionUID = 3069830602400919900L;


    @Value("${jwt.token}")
    private String jwtHeader;

    @Value("${jwt.secret}")
    private String jwtSecret;

    @Value("${jwt.expiration}")
    private Long jwtExpiration;

    private Clock clock = DefaultClock.INSTANCE;


    /**
     * 生成一个token
     * @param sysUser
     * @return
     */
    public String generateToken(SysUser sysUser){
        Claims claims = new DefaultClaims();
        claims.put("id", sysUser.getId());
        claims.put("username", sysUser.getUsername());
        claims.put("password", sysUser.getPassword());
        claims.put("account", sysUser.getAccount());
        claims.put("age", sysUser.getAge());
        claims.put("gender", sysUser.getGender());
        claims.put("createTime", sysUser.getCreateTime());
        return doGenerateToken(claims, sysUser.getId());
    }

    /**
     * 生成一个token
     * @param claims
     * @param username
     * @return
     */
    private String doGenerateToken(Map<String, Object> claims, String username) {
        final Date createDate = clock.now();
        final Date expirationDate = calculateExpirationDate(createDate);
        return Jwts.builder().setClaims(claims)
                .setSubject(username)
                .setIssuedAt(createDate)
                .setExpiration(expirationDate)
                .signWith(SignatureAlgorithm.HS512, jwtSecret)
                .compact();
    }


    /**
     * 计算过期时间
     * @param createDate
     * @return
     */
    private Date calculateExpirationDate(Date createDate) {
        long expiration = createDate.getTime() + jwtExpiration;
        return new Date(expiration);
    }

    /**
     * 验证token
     * @param token
     * @param userDetails
     * @return
     */
    public Boolean validateToken(String token, UserDetails userDetails) {
        SysUser user = (SysUser) userDetails;
        SysUser userForm = null;
        try {
            userForm = parseClaimToSysUser(getClaimFromToken(token));
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return (userForm.getUsername().equals(user.getUsername())
                && !isTokenExpired(token)
        );
    }


    /**
     * 验证token是否过期
     * @param token
     * @return
     */
    private Boolean isTokenExpired(String token) {
        final Date expiration = getExpirationDateFromToken(token);
        return expiration.before(clock.now());
    }

    /**
     * 获取token的过期时间
     * @param token
     * @return
     */
    public Date getExpirationDateFromToken(String token) {
        return getClaimFromToken(token).getExpiration();
    }


    /**
     * 将claims转换成SysUser
     * @param claims
     * @return
     */
    public SysUser parseClaimToSysUser(Claims claims) throws InvocationTargetException, IllegalAccessException {
        SysUser result = new SysUser();
        result.setId((String) claims.get("id"));
        result.setUsername((String) claims.get("username"));
        result.setPassword((String) claims.get("password"));
        result.setAccount((String) claims.get("account"));
        result.setGender((Integer) claims.get("gender"));
        result.setAge((Integer) claims.get("age"));
        result.setCreateTime((Date) claims.get("createTime"));
        return result;
    }


    /**
     * 从jwt中解析出Claims
     * @param token
     * @return
     */
    public Claims getClaimFromToken(String token){
        return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody();
    }

}
package com.calvin.boot.sys.filter;

import com.calvin.boot.sys.service.SysUserDetailService;
import com.calvin.boot.sys.tools.JwtTokenUtils;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
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.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;

/**
 * <p>核心过滤器,判断是否具备权限,是否需要校验 </p>
 *
 * @author Calvin
 * @date 2019/09/06
 * @since
 */
@Component
public class JwtAuthorizationTokenFilter extends OncePerRequestFilter {


    @Value("${jwt.token}")
    private String jwtHeader;

    @Autowired
    private JwtTokenUtils jwtTokenUtils;

    @Autowired
    private SysUserDetailService userDetailsService;


    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        logger.info("do jwt authorization token filter for url: " + httpServletRequest.getRequestURI());
        final String token = httpServletRequest.getHeader(this.jwtHeader);
        if(token != null){
            Claims claims = jwtTokenUtils.getClaimFromToken(token);
            String username = claims.get("username",String.class);
            UserDetails sysUser = this.userDetailsService.loadUserByUsername(username);
            if(jwtTokenUtils.validateToken(token, sysUser)){
                if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(sysUser, null, sysUser.getAuthorities());
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            }
        }
        filterChain.doFilter(httpServletRequest,httpServletResponse);
    }
}

package com.calvin.boot.config;

import com.calvin.boot.sys.filter.JwtAuthorizationTokenFilter;
import com.calvin.boot.sys.filter.JwtLoginFilter;
import com.calvin.boot.sys.service.SysUserDetailService;
import com.calvin.boot.sys.tools.Md5PasswordEncoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
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.password.PasswordEncoder;
import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * <p>
 *     SpringSecurity核心配置类
 * </p>
 *
 * @author Calvin
 * @date 2019/09/06
 * @since 0.1
 */
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    private SysUserDetailService sysUserDetailService;

    @Autowired
    private JwtAuthorizationTokenFilter jwtAuthorizationTokenFilter;


    /**
     * 简单配置过滤和校验
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling().authenticationEntryPoint(new JwtAuthorizationEntryPoint())
                .and().authorizeRequests()
                .antMatchers("/login/**").permitAll()
                .antMatchers(HttpMethod.OPTIONS, "/**").anonymous()
                .anyRequest().authenticated()
                .and().
                csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.addFilterBefore(jwtAuthorizationTokenFilter, UsernamePasswordAuthenticationFilter.class);

    }


    /**
     * 配置密码转换器和UserDetailService
     * @param builder 校验管理器
     * @throws Exception
     */
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder builder) throws Exception {
        builder.userDetailsService(sysUserDetailService).passwordEncoder(passwordEncoder());
    }

    /**
     * 密码管理器的Bean配置
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new Md5PasswordEncoder();
    }


    /**
     * 配置权限校验器Bean
     * @return
     * @throws Exception
     */
    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

}

JwtAuthorizationEntryPoint

/**
 * <p>
 *     如果没有凭证的处理,跳转回登录页面
 * </p>
 * @author jiawentao
 * @date 2019/09/11
 * @since
 */
public class JwtAuthorizationEntryPoint implements org.springframework.security.web.AuthenticationEntryPoint {

    private static final Logger logger = LoggerFactory.getLogger(JwtAuthorizationEntryPoint.class);

    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        logger.info("there is an request without authorization{}, remote url is {}", httpServletRequest.getRequestURL(), httpServletRequest.getRemoteHost());
        httpServletResponse.sendRedirect("/login/message");
    }
}

MD5PasswordEncoder

/**
 * <p>
 *     MD5PasswordEncoder进行字符串加密和判断是否匹配
 * </p>
 * @see org.springframework.security.crypto.password.PasswordEncoder
 * @see com.calvin.boot.config.SecurityConfig
 * @author Calvin
 * @date 2019/09/06
 * @since v0.1
 */
public class Md5PasswordEncoder implements PasswordEncoder {

    /**
     * 对字符串进行MD5加密, 32位小写
     * @param charSequence 要加密的字符串
     * @return
     */
    @Override
    public String encode(CharSequence charSequence) {
        return DigestUtils.md5DigestAsHex(charSequence.toString().getBytes());
    }


    /**
     * 判断密码是否正确,先把新的字符串加密
     * @param charSequence 未加密的字符串
     * @param s 已经加密过的字符串
     * @return
     */
    @Override
    public boolean matches(CharSequence charSequence, String s) {
        return this.encode(charSequence).equals(s);
    }

}

OrderController(用作测试)

/**
 * <p>测试 </p>
 *
 * @author Calvin
 * @date 2019/09/06
 * @since
 */
@RestController
@RequestMapping("/order")
public class OrderController {

    @RequestMapping("/test")
    public String testOrder(){
        return "success";
    }
}

至此大概写结束了,有小部分代码,实体封装和异常封装的类,代码就不贴上来了 现在进行登录测试 请求结果1
验证token
请求结果2

注解式参数

1:定义注解

/**
 * <p> 注解到参数的当前登录用户</p>
 *
 * @author jiawentao
 * @date 2019/09/15
 * @since
 */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoginUser {

}

注解解析器,通过JwtTokenUtils解析Header中的token直接拿到SysUser

/**
 * <p> LoginUser注解参数获取当前用户</p>
 *
 * @author jiawentao
 * @date 2019/09/15
 * @since
 */
@Component
public class LoginUserHandlerResolver implements HandlerMethodArgumentResolver {


    @Value("${jwt.token}")
    private String jwtHeader;


    @Autowired
    private JwtTokenUtils jwtTokenUtils;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().isAssignableFrom(SysUser.class)
                && parameter.hasParameterAnnotation(LoginUser.class);
    }


    /**
     * 将参数解析成实体
     * @param parameter 方法参数
     * @param mavContainer 视图容器
     * @param webRequest 本地请求
     * @param binderFactory 参数绑定
     * @return
     * @throws Exception
     */
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String header = webRequest.getHeader(jwtHeader);
        return jwtTokenUtils.parseClaimToSysUser(jwtTokenUtils.getClaimFromToken(header));
    }
}

配置参数解析器

@Configuration
public class WebMvcConfig  extends WebMvcConfigurationSupport {
    @Autowired
    private LoginUserHandlerResolver loginUserHandlerResolver;

    @Override
    protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(loginUserHandlerResolver);
    }
}

小结

1:简单使用SpringBootSecurity做了一个权限校验
2:融入进JWT令牌
3:编写注解式获取当前登录用户信息

问题总结

1: 对SpringBootSecurity框架了解不够详细,只能简单使用,也是导致这次更新时间比较长的原因
2: 没有融入进redis等缓存服务,导致此项目暂时不支持集群部署
3:直接采用Mybatis-Plus框架,对没有Mbatis基础的同学不友好
4:应该更加注重编码规范和注释,贴代码的过程中才发现注释太少

项目地址: https://gitee.com/devilscode/boot-security-jwt

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部