部分引自 www.javaboy.org
测试数据库脚本
/*
Navicat MySQL Data Transfer
Source Server : localhost
Source Server Version : 50717
Source Host : localhost:3306
Source Database : security
Target Server Type : MYSQL
Target Server Version : 50717
File Encoding : 65001
Date: 2018-07-28 15:26:51
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) DEFAULT NULL,
`nameZh` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES ('1', 'dba', '数据库管理员');
INSERT INTO `role` VALUES ('2', 'admin', '系统管理员');
INSERT INTO `role` VALUES ('3', 'user', '用户');
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`enabled` tinyint(1) DEFAULT NULL,
`locked` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'root', '$2a$10$WuUO9k/3LfTGzMEAKxNtAenttd9ulTq7wTj17ojqbU44Q5rwN/mWu', '1', '0');
INSERT INTO `user` VALUES ('2', 'admin', '$2a$10$WuUO9k/3LfTGzMEAKxNtAenttd9ulTq7wTj17ojqbU44Q5rwN/mWu', '1', '0');
INSERT INTO `user` VALUES ('3', 'sang', '$2a$10$WuUO9k/3LfTGzMEAKxNtAenttd9ulTq7wTj17ojqbU44Q5rwN/mWu', '1', '0');
-- ----------------------------
-- Table structure for user_role
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uid` int(11) DEFAULT NULL,
`rid` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT INTO `user_role` VALUES ('1', '1', '1');
INSERT INTO `user_role` VALUES ('2', '1', '2');
INSERT INTO `user_role` VALUES ('3', '2', '2');
INSERT INTO `user_role` VALUES ('4', '3', '3');
SET FOREIGN_KEY_CHECKS=1;
注意:密码可以自己用security产生,这里偷个懒,写成了一样的,测试时不影响
IDEA新建项目
添加web,security,mysql driver,mybatis 依赖
添加数据库版本和druid连接池依赖
com.alibaba
druid-spring-boot-starter
1.1.10
mysql
mysql-connector-java
runtime
5.1.47
application.properties
spring.datasource.url=jdbc:mysql:///security_test
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.username=root
spring.datasource.password=root
创建实体类User
权限验证要求我们将用户类实现一个接口 UserDetails
package org.javaboy.security_db.bean;
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;
public class User implements UserDetails {
private Integer id;
private String username;
private String password;
private Boolean enabled;
private Boolean locked;
private List roles;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Override
public String getUsername() {
return username;
}
/**
* 账号是否未过期,正常是数据库有相应字段,若过期返回false,未过期返回true
* 我们的数据库因为没有设置该字段,所以我们直接写true
* @return
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* 账号是否未锁定,我们数据库中有该字段,所以直接返回我们的字段即可
* 同时删除对应的get方法,因为这个方法相当于get
* enabled同理
* @return
*/
@Override
public boolean isAccountNonLocked() {
return !locked;
}
/**
* 凭证(密码)是否过期
* @return
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
public void setUsername(String username) {
this.username = username;
}
/**
* 返回用户的所有角色
* @return
*/
@Override
public Collection extends GrantedAuthority> getAuthorities() {
// 将roles进行整理
List authorities = new ArrayList<>();
for (Role role : roles) {
// 角色认证的要求,角色名必须是ROLE开始的(如果数据库中查出来的数据就是ROLE开始,该字符串可以省略)
authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getName()));
}
return authorities;
}
@Override
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
public List getRoles() {
return roles;
}
public void setRoles(List roles) {
this.roles = roles;
}
}
Role
package org.javaboy.security_db.bean;
public class Role {
private Integer id;
private String name;
private String nameZh;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNameZh() {
return nameZh;
}
public void setNameZh(String nameZh) {
this.nameZh = nameZh;
}
}
准备Service和Mapper
service
package org.javaboy.security_db.service;
import org.javaboy.security_db.bean.User;
import org.javaboy.security_db.mapper.UserMapper;
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;
@Service
public class UserService implements UserDetailsService { // Service也需要实现一个接口
@Autowired
UserMapper userMapper;
/**
* 根据用户名返回用户信息
* @param s 用户名
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(s);
if (user == null) {
throw new UsernameNotFoundException("用户不存在");
}
user.setRoles(userMapper.getRolesById(user.getId()));
return user;
}
}
mapper
package org.javaboy.security_db.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.javaboy.security_db.bean.Role;
import org.javaboy.security_db.bean.User;
import java.util.List;
@Mapper
public interface UserMapper {
User loadUserByUsername(String username);
List getRolesById(Integer id);
}
mapper.xml
这里因为数据量比较小,采取了in
security配置类
package org.javaboy.security_db.config;
import org.javaboy.security_db.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserService userService;
/**
* 指定userService
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/dba/**").hasRole("dba")
.antMatchers("/user/**").hasRole("user")
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.and()
.csrf().disable();
}
}
pom配置资源目录
src/main/resources
src/main/java
**/*.xml
准备controller接口
package org.javaboy.security_db.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello security";
}
@GetMapping("/admin/hello")
public String admin() {
return "hello admin";
}
@GetMapping("/dba/hello")
public String dba() {
return "hello dba";
}
@GetMapping("/user/hello")
public String user() {
return "hello user";
}
}
启动项目测试