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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章