本项目使用 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:
看后台:
完成了