spring boot+spring security+jwt实现安全

本项目使用 spring boot,spring security,jwt,mybatis-plus

 

关于mybatis-plus代码生成的,请看我的另外一篇博客

https://blog.csdn.net/qq_42151769/article/details/103801366

自定义权限不足返回,自定义未登录返回

表结构:

 

 

项目截图

 

 

 

添加依赖:

<?xml version="1.0" encoding="UTF-8"?>
<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.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wm</groupId>
    <artifactId>rolesys</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>rolesys</name>
    <description>权限系统设计</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>


        <!--security 依赖-->
        <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.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </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>

        <!--jwt依赖-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>

        <!-- commons-lang3依赖 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>6.0.6</version>
        </dependency>

        <!--mybatis-plus依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.0</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

配置文件: application.yml

### 自定义spring security白名单url
security:
  ignore:
    urls:
      - /yu/login
spring:
  datasource:
    username: root
    password: AI@123ai
    url: jdbc:mysql://172.16.19.28:3306/ywm_test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2b8
mybatis-plus:
  mapper-locations: classpath*:/mapper/*.xml
logging:
  level:
    root : INFO
    com.hfepay: DEBUG

#### 自定义jwt参数
jwt:
  tokenHeader: token #JWT存储的请求头
  secret: jwt_secret #JWT加解密使用的密钥
  expiration: 604800 #JWT的超期限时间(60*60*24)

定义读取配置文件的实体类:

jwtPropertis.java

package com.wm.rolesys.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/***
 * @ClassName: JwtProperties
 * @Description: 读取定义的jwt配置
 * @Author: wm_yu
 * @Create_time: 16:18 2019-12-31
 */
@ConfigurationProperties(prefix = "jwt")
@Component
@Data
public class JwtProperties {
    private String tokenHeader;
    private String secret;
    private Integer expiration;
}

自定义spring security白名单url,不进行认证,直接访问

IgnoreUrlsConfig.java
package com.wm.rolesys.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.List;

/***
 * @ClassName: IgnoreUrlsConfig
 * @Description: 不进行权限拦截的url, 如登录, 注册等接口
 * @Author: wm_yu
 * @Create_time: 17:05 2019-12-31
 */
@ConfigurationProperties(prefix = "security.ignore")
@Component
@Data
public class IgnoreUrlsConfig {
    private List<String> urls;
}

 

jwt工具类: jwtUtil

package com.wm.rolesys.util;

import com.wm.rolesys.config.JwtProperties;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/***
 * @ClassName: JwtTokenUtil
 * @Description: jwt工具类
 * @Author: wm_yu
 * @Create_time: 16:14 2019-12-31
 */
@Component
@Slf4j
@AllArgsConstructor
public class JwtTokenUtil {


    private final JwtProperties jwtProperties;

    /**
     * 注入JwtProperties
     *
     * JWT Claims
     *
     * “iss” (issuer)  发行人
     *
     * “sub” (subject)  主题
     *
     * “aud” (audience) 接收方 用户
     *
     * “exp” (expiration time) 到期时间
     *
     * “nbf” (not before)  在此之前不可用
     *
     * “iat” (issued at)  jwt的签发时间
     *
     * “jti” (JWT ID)  jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
     *
     */
    private static final String CLAIM_KEY_USERNAME = "sub";

    /**
     * 创建时间key
     */
    private static final String CLAIM_KEY_CREATED = "created";

    /**
     * 根据负责生成JWT的token
     */
    private String generateToken(Map<String, Object> claims) {
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate())
                .signWith(SignatureAlgorithm.HS512, jwtProperties.getSecret())
                .compact();
    }

    /**
     * 从token中获取JWT中的负载
     */
    private Claims getClaimsFromToken(String token) {
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(jwtProperties.getSecret())
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            log.info("JWT格式验证失败:{}", token);
        }
        return claims;
    }

    /**
     * 生成token的过期时间
     */
    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + jwtProperties.getExpiration() * 1000);
    }

    /**
     * 从token中获取登录用户名
     */
    public String getUserNameFromToken(String token) {
        String username;
        try {
            Claims claims = getClaimsFromToken(token);
            username = claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    /**
     * 验证token是否还有效
     *
     * @param token       客户端传入的token
     * @param userDetails 从数据库中查询出来的用户信息
     */
    public boolean validateToken(String token, UserDetails userDetails) {
        String username = getUserNameFromToken(token);
        return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
    }

    /**
     * 判断token是否已经失效
     */
    private boolean isTokenExpired(String token) {
        Date expiredDate = getExpiredDateFromToken(token);
        return expiredDate.before(new Date());
    }

    /**
     * 从token中获取过期时间
     */
    private Date getExpiredDateFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims.getExpiration();
    }

    /**
     * 根据用户信息生成token
     */
    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateToken(claims);
    }

    /**
     * 当原来的token没过期时是可以刷新的
     *
     * @param token 带tokenHead的token
     */
    public String refreshHeadToken(String token) {
        if(StringUtils.isEmpty(token)){
            return null;
        }
        //token校验不通过
        Claims claims = getClaimsFromToken(token);
        if(claims==null){
            return null;
        }
        //如果token已经过期,不支持刷新
        if(isTokenExpired(token)){
            return null;
        }
        //如果token在30分钟之内刚刷新过,返回原token
        if(tokenRefreshJustBefore(token,30*60)){
            return token;
        }else{
            //设置创建时间
            claims.put(CLAIM_KEY_CREATED, new Date());
            return generateToken(claims);
        }
    }

    /**
     * 判断token在指定时间内是否刚刚刷新过
     * @param token 原token
     * @param time 指定时间(秒)
     */
    private boolean tokenRefreshJustBefore(String token,int time) {
        Claims claims = getClaimsFromToken(token);
        Date created = claims.get(CLAIM_KEY_CREATED, Date.class);
        Date refreshDate = new Date();
        //刷新时间在创建时间的指定时间内
        long l = time * (1000L);
        return refreshDate.after(created)&&(refreshDate.getTime() - l < 0);
    }

}

定义spring security的核心配置:

WebSecurityConfig.java
package com.wm.rolesys.config;

import com.wm.rolesys.jwt.JwtTokenFilter;
import com.wm.rolesys.security.RestAuthenticationEntryPoint;
import com.wm.rolesys.security.RestfulAccessDeniedHandler;
import com.wm.rolesys.security.UserDetailServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.List;

/***
 * @ClassName: WebSecurityConfig
 * @Description: spring security配置
 * @Author: wm_yu
 * @Create_time: 17:04 2019-12-31
 */
@EnableConfigurationProperties(value = {IgnoreUrlsConfig.class})
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true) //允许开启security的方法级别的安全
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

    @Autowired
    private UserDetailServiceImpl userService;

    @Autowired
    private JwtTokenFilter jwtTokenFilter;

    @Autowired
    private IgnoreUrlsConfig ignoreUrlsConfig;


    @Bean
    public JwtTokenFilter authenticationTokenFilterBean() throws Exception {
        return jwtTokenFilter;
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure( AuthenticationManagerBuilder auth ) throws Exception {
        auth.userDetailsService( userService ).passwordEncoder( new BCryptPasswordEncoder() );
    }

    /**
     * HTTP请求安全处理
     * @param httpSecurity
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity httpSecurity ) throws Exception {

        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity
                .authorizeRequests();
        List<String> ignoreUrlList = ignoreUrlsConfig.getUrls();
        //不需要保护的资源路径允许访问
        for (String url :ignoreUrlList) {
            registry.antMatchers(url).permitAll();
        }
        //允许跨域请求的OPTIONS请求
        registry.antMatchers(HttpMethod.OPTIONS)
                .permitAll();
        // 任何请求需要身份认证
        registry.and()
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                // 关闭跨站请求防护及不使用session
                .and()
                .csrf()
                .disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                // 自定义权限拒绝处理类
                .and()
                .exceptionHandling()
                //权限不足 如果权限不足,restfulAccessDeniedHandler,(排除白名单之外的接口)
                .accessDeniedHandler(restfulAccessDeniedHandler())
                //未登录,如果未登录,会进入restAuthenticationEntryPoint中,(排除白名单之外的接口)
                .authenticationEntryPoint(restAuthenticationEntryPoint())
                .and()
                // 使用前文自定义的 Token过滤器
                .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);

        httpSecurity.headers().cacheControl();
    }

    /**
     *  权限不足时访问,返回
     * @return
     */
    @Bean
    public RestfulAccessDeniedHandler restfulAccessDeniedHandler() {
        return new RestfulAccessDeniedHandler();
    }

    /**
     *未登录
     * @return
     */
    @Bean
    public RestAuthenticationEntryPoint restAuthenticationEntryPoint() {
        return new RestAuthenticationEntryPoint();
    }

}

jwt过滤设置,辅助security进行认证

JwtTokenFilter.java
package com.wm.rolesys.jwt;

import com.wm.rolesys.config.JwtProperties;
import com.wm.rolesys.constant.CommonConstant;
import com.wm.rolesys.security.UserDetailServiceImpl;
import com.wm.rolesys.util.JwtTokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
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;

/***
 * @ClassName: JwtTokenFilter
 * @Description: jwt过滤器    该Filter 保证每次请求一定会过滤
 * @Author: wm_yu
 * @Create_time: 16:34 2019-12-31
 */
@Slf4j
@Component
public class JwtTokenFilter extends OncePerRequestFilter {
    @Autowired
    private UserDetailServiceImpl userDetailService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private JwtProperties jwtProperties;

    @Override
    protected void doFilterInternal ( HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        String authHeader = request.getHeader(jwtProperties.getTokenHeader());
        //token必须以Beare开头
        if (ObjectUtils.isNotEmpty(authHeader) && authHeader.startsWith(CommonConstant.TOKEN_PREFIX)) {
            //截取token
            final String authToken = authHeader.substring(CommonConstant.TOKEN_PREFIX.length() );
            //冲token中获取到username
            String username = jwtTokenUtil.getUserNameFromToken(authToken);
            if (ObjectUtils.isNotEmpty(username) && SecurityContextHolder.getContext().getAuthentication() == null) {
                //获取到用户信息
                UserDetails userDetails = userDetailService.loadUserByUsername(username);
                //校验token是否过期
                if (jwtTokenUtil.validateToken(authToken,userDetails)) {
                    log.info("token未过期,token:[{}],用户名:[{}]",authToken,username);
                    //构建spring security认证需要的数据,存入上下文中
                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                            userDetails, null, userDetails.getAuthorities());
                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(
                            request));
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            }
        }
        chain.doFilter(request, response);
    }
}

定义UserDetail:

package com.wm.rolesys.security;

import com.wm.rolesys.entity.Role;
import com.wm.rolesys.entity.User;
import lombok.Data;
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;

/***
 * @ClassName: UserDetailImpl
 * @Description: 用户详情类, 实现spring security的userDetail
 * @Author: wm_yu
 * @Create_time: 15:59 2019-12-31
 */
@Data
public class UserDetailImpl implements UserDetails {

    /**
     * 用户信息(基本信息)
     */
    private User user;

    /**
     * 用户角色列表
     */
    private List<Role> roleList;


    /**
     * 返回角色列表(暂定为权限),名称
     * @return
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> authorities = new ArrayList<>();
        for (Role role : roleList) {
            authorities.add(new SimpleGrantedAuthority(role.getName() ) );
        }
        return authorities;
    }

    @Override
    public String getPassword() {
        return this.user.getPassword();
    }

    @Override
    public String getUsername() {
        return this.user.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

定义userDetailService:  处理查询数据库的数据

package com.wm.rolesys.security;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wm.rolesys.entity.Role;
import com.wm.rolesys.entity.User;
import com.wm.rolesys.mapper.RoleMapper;
import com.wm.rolesys.mapper.UserMapper;
import org.apache.commons.lang3.ObjectUtils;
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.ArrayList;
import java.util.List;
import java.util.Optional;

/***
 * @ClassName: UserDetailServiceImpl
 * @Description: 自定义查询数据库的userService, 实现spring security的userDetailService
 * @Author: wm_yu
 * @Create_time: 16:50 2019-12-31
 */
@Service
public class UserDetailServiceImpl implements UserDetailsService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 查询数据库,通过username查询用户信息
        UserDetailImpl userDetail = new UserDetailImpl();
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username",username);
        wrapper.last("limit 1");
        User user = Optional.ofNullable(userMapper.selectOne(wrapper)).orElse(new User());
        userDetail.setUser(user);
        //查询角色信息
        if(ObjectUtils.isNotEmpty(user.getId())){
            QueryWrapper<Role> ew = new QueryWrapper<>();
            ew.last(String.format("inner join user_role ur on id = ur.role_id where ur.user_id = %s",user.getId()));
            List<Role> roles = Optional.ofNullable(roleMapper.selectList(ew)).orElse(new ArrayList<>());
            userDetail.setRoleList(roles);
        }
        return userDetail;
    }
}

自定义没有权限时返回:

package com.wm.rolesys.security;

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;

/***
 * @ClassName: RestfulAccessDeniedHandler
 * @Description: 自定义返回结果:没有权限访问时
 * @Author: wm_yu
 * @Create_time: 15:38 2019-12-11
 */
public class RestfulAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request,
                       HttpServletResponse response,
                       AccessDeniedException e) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        response.getWriter().println("权限不足..");
        response.getWriter().flush();
    }
}

 

定义未登录时返回:
 

package com.wm.rolesys.security;

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;

/***
 * @ClassName: RestfulAccessDeniedHandler
 * @Description: 自定义返回结果:没有权限访问时
 * @Author: wm_yu
 * @Create_time: 15:38 2019-12-11
 */
public class RestfulAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request,
                       HttpServletResponse response,
                       AccessDeniedException e) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        response.getWriter().println("权限不足..");
        response.getWriter().flush();
    }
}

下面是Mybatis的一些类:

数据库实体类:

角色类

package com.wm.rolesys.entity;

import lombok.Data;

import java.io.Serializable;

/***
 * @ClassName: Role
 * @Description: 角色实体类
 * @Author: wm_yu
 * @Create_time: 16:03 2019-12-31
 */
@Data
public class Role implements Serializable {
    private static final long serialVersionUID = -6872536197605409813L;
    private Long id;
    private String name;

}

用户类:

package com.wm.rolesys.entity;

import lombok.Data;

import java.io.Serializable;

/***
 * @ClassName: User
 * @Description: 用户实体类
 * @Author: wm_yu
 * @Create_time: 16:00 2019-12-31
 */
@Data
public class User implements Serializable {
    private static final long serialVersionUID = 6087479793127678076L;

    private Long id;

    /**
     * 遵循security的命名 使用username
     */
    private String username;

    /**
     * 遵循security的命名 使用password
     */
    private String password;

}

角色用户关系类:

package com.wm.rolesys.entity;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.Accessors;

import java.io.Serializable;

/**
 * <p>
 * 
 * </p>
 *
 * @author wm_yu
 * @since 2020-01-02
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ToString(callSuper = true)
public class UserRole implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long userId;

    private Long roleId;


}

mapper接口:

package com.wm.rolesys.mapper;


import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wm.rolesys.entity.Role;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author wm_yu
 * @since 2020-01-02
 */
public interface RoleMapper extends BaseMapper<Role> {

}
package com.wm.rolesys.mapper;


import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wm.rolesys.entity.User;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author wm_yu
 * @since 2020-01-02
 */
public interface UserMapper extends BaseMapper<User> {

}

 

package com.wm.rolesys.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wm.rolesys.entity.UserRole;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author wm_yu
 * @since 2020-01-02
 */
public interface UserRoleMapper extends BaseMapper<UserRole> {

}

mapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wm.codedemo.mapper.RoleMapper">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.wm.rolesys.entity.Role">
        <result column="id" property="id" />
        <result column="name" property="name" />
    </resultMap>

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, name
    </sql>

</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wm.codedemo.mapper.UserMapper">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.wm.rolesys.entity.User">
        <result column="id" property="id" />
        <result column="username" property="username" />
        <result column="password" property="password" />
    </resultMap>

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, username, password
    </sql>

</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wm.codedemo.mapper.UserRoleMapper">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.wm.rolesys.entity.UserRole">
        <result column="user_id" property="userId" />
        <result column="role_id" property="roleId" />
    </resultMap>

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        user_id, role_id
    </sql>

</mapper>

定义常量类:

package com.wm.rolesys.constant;

/***
 * @ClassName: CommonConstant
 * @Description: 常量
 * @Author: wm_yu
 * @Create_time: 16:42 2019-12-31
 */
public class CommonConstant {
    public static String TOKEN_PREFIX = "Bearer";
}

定义测试用的controller
 

package com.wm.rolesys.controller;

import com.wm.rolesys.constant.CommonConstant;
import com.wm.rolesys.security.UserDetailServiceImpl;
import com.wm.rolesys.util.JwtTokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/***
 * @ClassName: UserController
 * @Description:
 * @Author: wm_yu
 * @Create_time: 17:25 2019-12-31
 */
@RestController
@RequestMapping("/yu")
@Slf4j
public class UserController {

    @Autowired
    private UserDetailServiceImpl userDetailService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @GetMapping("/test")
    public String test(String what){
        log.info("通过权限认证");
       return String.format("hello request test %s",what);
    }

    @GetMapping("/login")
    public String login(String username){
        log.info("不需要权限校验..成功");
        //查询数据库
        UserDetails userDetails = userDetailService.loadUserByUsername(username);
        String token = jwtTokenUtil.generateToken(userDetails);
        return String.format(String.format("%s %s", CommonConstant.TOKEN_PREFIX,token));
    }


}

别忘记了在启动类上面添加注解:

package com.wm.rolesys;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.wm.rolesys.mapper")
public class RolesysApplication {

    public static void main(String[] args) {
        SpringApplication.run(RolesysApplication.class, args);
    }

}

下面是测试结果

看下测试接口:

登录接口,不需要验证,返回token

 

 

请求成功:

 

测试要权限的接口:

先不给定token,如下

 

 

 

可以看到根本就没有进入请求,被spring security拦截了

添加token:

看后台:

 

完成了

 

 

 

 

发布了93 篇原创文章 · 获赞 26 · 访问量 3万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章