项目我都贴源码,方便大家拷贝!希望能帮助刚入门spring security 小伙伴,那我写这篇博文的意义就实现了!加油,努力的人最幸运*_*
项目目录:
- 引入spring security 依赖,
<?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.1.13.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>security</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>security</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.1</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.56</version>
</dependency>
<!-- 权限相关依赖(security和jwt)-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 配置数据源
yaml 文件
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/security-jwt?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8
username: root
password: 8456555
jpa:
show-sql: true
mybatis-plus:
mapper-locations: classpath:/mapper/*Mapper.xml
type-aliases-package: com.example.entity
configuration:
map-underscore-to-camel-case: true
logging:
level:
com.example.mapper: debug
jwt:
tokenHeader: Authorization
tokenPrefix: Bearer
secret: lanjwt
expiration: 3600
rememberExpiration: 604800
properties 文件
server.port=9999
server.tomcat.uri-encoding=UTF-8
server.servlet.context-path= /qiu
#spring.security.user.name=qiuny
#spring.security.user.password= 123456
jwt.sorket = good_to_bad
- 配置mybatis-plus文件
3.1 MyBatisMapperScannerConfig.java
package com.example.security.config;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@AutoConfigureAfter(MybatisPlusConfig.class)
public class MyBatisMapperScannerConfig {
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
mapperScannerConfigurer.setBasePackage("com.lan.demo.mapper");
return mapperScannerConfigurer;
}
}
3.2 MybatisPlusConfig.java
package com.example.security.config;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
1. mybatis-plus配置
*/
@Configuration
public class MybatisPlusConfig {
/**
* mybatis-plus分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor page = new PaginationInterceptor();
page.setDialectType("mysql");
return page;
}
}
- 配置springsecurity 文件
4.1 ExtendSecurityUser.java. 自定义扩展User类
package com.example.security.config;
import com.example.security.entitys.UserEntity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import java.util.List;
/**
* <p>
* 考虑到user中只有账号和密码,为了获取到原始的UserEntity对象,专门创建这个类对
* spring security 自带的User类进行扩展
* 扩展spring security的用户对象,返回用户完整信息
* </p>
*
* @author qiu
* @since 2020-03-87
*/
public class ExtendSecurityUser extends User {
/**
* 原始对象
* UserEntity originalUser :传入原始的UserEntity对象
* List<GrantedAuthority> authorities :创建角色、权限信息集合
*/
private UserEntity originalUser;
public ExtendSecurityUser(UserEntity originalUser, List<GrantedAuthority> authorities){
/**
* 调用父类构造器
*/
super(originalUser.getUserName(),originalUser.getUserPassword(),authorities);
/**
* 给本类的this.originalUser 赋值
*/
this.originalUser = originalUser;
}
/**
* 对外提供的获取原始UserEntity 对象 的get方法
* @return
*/
public UserEntity getOriginalUser() {
return originalUser;
}
}
4.2 WebAppSecurityConfig.java
package com.example.security.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import javax.sql.DataSource;
/**
* @ClassName WebAppSecurityConfig
* @Author QiuKing
* @EnableWebSecurity 开启security环境注解
* @Date 2020/3/1916:15
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled =true)
public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 描述: 注入数据源
* @Author QiuKing
* @Date 2020/3/26 15:35
*/
@Autowired
private DataSource dataSource;
@Autowired
private MyUserDetailsServiceImpl myUserDetailsService;
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception {
// 1、内存登录
// builder.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
// .withUser("qiuny")
// .password(new BCryptPasswordEncoder().encode("123456"))
// .roles("ADMIN","学徒")
// .and()
// .withUser("yangy")
// .password(new BCryptPasswordEncoder().encode("123456"))
// .roles("BOSS")
// .authorities("ADD","DELETE","UPDATE","SELECT","内门弟子")
// ;
// 2、数据库登录
builder.userDetailsService(myUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());
// super.configure(builder);
}
@Override
protected void configure(HttpSecurity security) throws Exception {
/**
* 描述: <br>重写父类方法 configure
* authorizeRequests()//对请求进行授权
* .antMatchers("/test")//无条件访问路径
* permitAll()//无条件访问路径
* .authorizeRequests()//对请求进行授权
* .anyRequest() // 任意请求
* .authenticated();// 需要登录以后才可以访问
* .formLogin(); // 开启默认登录
* .loginPage("login.html") //设置登录页,提交表单action:login.html method="post"
* .loginProcessingUrl() //登录地址:一旦开启就会覆盖 loginPage默认提交地址
* .defaultSuccessUrl() // 默认登录成功要跳转的页面路径
* .usernameParameter("userName").passwordParameter("passWord") // 修改默认登录表单属性字段名
* .disable() 禁用csrf跨越请求功能,如果安全性高就可以用它
* .logout() 开启退出功能
* .logoutUrl("/do/logout") 指定退出提交地址
* .logoutSuccessUrl("/user/logoutSuccess").permitAll() 退出成功访问地址
* login_url: http://localhost:9999/qiu/do/login?loginName=qiuny&loginPassword=123456
* out_url: http://localhost:9999/qiu/do/logout
* .exceptionHandling() 访问拒绝开启
* .accessDeniedPage("/error/no/auth") 访问被拒绝访问地址
* @Author QiuKing
* @Date 2020/3/19 17:11
*/
security
.authorizeRequests()
.antMatchers("/user/test")
.permitAll()
.antMatchers("/user/level1")
.hasRole("学徒")
.antMatchers("/user/level2")
.hasAuthority("内门弟子")
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginProcessingUrl("/do/login")
.usernameParameter("loginName")
.passwordParameter("loginPassword")
.defaultSuccessUrl("/user/loginSuccess")
.and()
.csrf()
.disable()
.logout()
.logoutUrl("/do/logout")
.logoutSuccessUrl("/user/logoutSuccess").permitAll()
.and()
.exceptionHandling()
.accessDeniedPage("/error/no/auth")
;
//super.configure(security);
}
}
4.3 MyUserDetailsServiceImpl.java
package com.example.security.config;
import com.example.security.entitys.Permission;
import com.example.security.entitys.Role;
import com.example.security.entitys.UserEntity;
import com.example.security.service.IPermissionService;
import com.example.security.service.IRoleService;
import com.example.security.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
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.Component;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
/**
* 根据表单提交的账号查询user对象,并装配角色、权限信息
* @ClassName MyUserDetailsServiceImpl
* @Author QiuKing
* @Date 2020/3/2615:49
*/
@Component
public class MyUserDetailsServiceImpl implements UserDetailsService {
@Autowired
private IUserService iUserService;
@Autowired
private IPermissionService iPermissionService;
@Autowired
private IRoleService iRoleService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserEntity user = iUserService.findUserByName(username);
if (StringUtils.isEmpty(user)){
throw new UsernameNotFoundException("用户不存在");
}else {
String userId = user.getUserId();
// 获取角色集合
List<Role> roleList = iRoleService.getRoleListByUserId(userId);
// 获取权限集合
List<Permission> permissionList = iPermissionService.permissionListByUserId(userId);
//给用户设置角色权限信息
List<GrantedAuthority> authorities = new ArrayList<>();
// 遍历角色
for (Role role : roleList){
String roleName = "ROLE_"+role.getRoleName();
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(roleName);
authorities.add(simpleGrantedAuthority);
}
// 遍历权限
for (Permission permission : permissionList){
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(permission.getPermissionName());
authorities.add(simpleGrantedAuthority);
}
// authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
// authorities.add(new SimpleGrantedAuthority("ROLE_SELECT"));
// authorities.add(new SimpleGrantedAuthority("UPDATE"));
// 把admin对象和authorities 封装到 UserDetails中
// String password = user.getUserPassword();
// return new User(username,password,authorities);
ExtendSecurityUser admin = new ExtendSecurityUser(user, authorities);
return admin;
}
}
}
4.4 UserController.java
package com.example.security.controller;
import com.example.security.service.IUserService;
import com.example.security.utils.ResultUtil;
import com.sun.deploy.net.HttpResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpRequest;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import sun.plugin.liveconnect.SecurityContextHelper;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 描述: 用户接口
* @Author QiuKing
* @Date 2020/3/19 10:09
*/
@RestController
@RequestMapping(value = "/user")
public class UserController {
@Value("${jwt.sorket}")
private String sorket= null;
/**
* 描述: <br>获得日志
* @Author QiuKing
* @Date 2020/3/19 15:42
*/
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private IUserService userService;
@RequestMapping("/level1")
public ResultUtil level1(){
logger.info("可以访问");
return ResultUtil.success("恭喜你,你是学徒可以访问level1");
}
@RequestMapping("/level2")
public ResultUtil level2(){
logger.info("内门弟子");
return ResultUtil.success("恭喜你,你是‘内门弟子’可以访问level2");
}
@GetMapping("/list")
@PreAuthorize("hasRole('ADMIN')")
public ResultUtil list() {
ResultUtil result = userService.getList();
result.setTest_msg(sorket+"只有管理员才能获取用户列表");
return result;
}
@GetMapping("/test")
public ResultUtil test(){
return ResultUtil.success("不需要登录也能访问我");
}
@RequestMapping("/loginSuccess")
public ResultUtil login(@AuthenticationPrincipal UserDetails userDetails){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
ResultUtil<Object> resultUtil = new ResultUtil<>();
resultUtil.setSuccess(true);
resultUtil.setMsg("恭喜你,登录成功");
resultUtil.setData(authentication.getPrincipal());
logger.info("登录成功");
return resultUtil;
}
@RequestMapping("/logoutSuccess")
public ResultUtil logout(HttpServletRequest request, HttpServletResponse response){
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!StringUtils.isEmpty(auth)){
new SecurityContextLogoutHandler().logout(request, response, auth);
// 清除当前用户权限缓存
}
logger.info("退出成功");
return ResultUtil.success("退出成功");
}
}
- 实体类
5.1 权限
package com.example.security.entitys;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* <p>
* 权限实体类
* </p>
*
* @author qiu
* @since 2020-03-87
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class Permission implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 权限编号
*/
@TableId
private String permissionId;
/**
* 权限标识
*/
private String permissionName;
/**
* 授权url
*/
private String permissionUrl;
/**
* 描述
*/
private String permissionComment;
/**
* 权限状态,0正常,-1删除
*/
private String permissionStatus;
}
5.2 角色
package com.example.security.entitys;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* <p>
* 角色表 服务实现类
* </p>
*
* @author qiu
* @since 2020-03-87
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class Role implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 角色编号
*/
@TableId
private String roleId;
/**
* 角色名称
*/
private String roleName;
/**
* 角色状态,0正常,-1删除
*/
private String roleStatus;
}
5.3 用户
package com.example.security.entitys;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @ClassName UserEntity
* @Author QiuKing
* @Date 2020/3/1911:08
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("user")
public class UserEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 用户编号
*/
@TableId
private String userId;
/**
* 用户名
*/
private String userName;
/**
* 用户手机号码
*/
private String userPhone;
/**
* 用户密码
*/
private String userPassword;
/**
* 用户最近一次登录时间
*/
private String userLastLoginTime;
/**
* 用户注册时间
*/
private String userCreateTime;
/**
* 用户状态,0正常,-1删除
*/
private String userStatus;
}
- service实现类
6.1 PermissionServiceImpl
package com.example.security.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.security.entitys.Permission;
import com.example.security.mapper.PermissionMapper;
import com.example.security.service.IPermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 权限实现类
* </p>
*
* @author qiu
* @since 2020-03-87
*/
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements IPermissionService {
@Autowired
private PermissionMapper permissionMapper;
@Override
public List<Permission> permissionListByUserId(String userId) {
List<Permission> list = permissionMapper.permissionListByUserId(userId);
return list;
}
}
6.2 RoleServiceImpl
package com.example.security.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.security.entitys.Role;
import com.example.security.mapper.RoleMapper;
import com.example.security.service.IRoleService;
import com.example.security.utils.Contant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 角色表 服务实现类
* </p>
*
* @author qiu
* @since 2020-03-87
*/
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IRoleService {
@Autowired
private RoleMapper roleMapper;
@Override
public List<Role> getRoleListByUserId(String userId) {
return roleMapper.getRoleListByUserId(userId);
}
}
6.3 UserServiceImpl
package com.example.security.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.security.entitys.UserEntity;
import com.example.security.mapper.UserMapper;
import com.example.security.service.IUserService;
import com.example.security.utils.Contant;
import com.example.security.utils.ResultUtil;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 描述: <br>
* @Author QiuKing
* @Date 2020/3/19 11:10
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,UserEntity> implements IUserService {
@Override
public ResultUtil getList() {
QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
wrapper.eq("user_status",Contant.ZERO);
try {
List<UserEntity> list = this.list(wrapper);
return ResultUtil.success(list);
}catch (Exception e){
return ResultUtil.error(e.toString());
}
}
@Override
public UserEntity findUserByName(String username) {
QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
wrapper.eq("user_name",username)
.eq("user_status",Contant.ZERO);
UserEntity one = this.getOne(wrapper);
return one;
}
}
需要源码的留言,劳动是很辛苦的;