本項目使用 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:
看後臺:
完成了