Spring Security 是 Spring 家族的一个安全框架, 提供了全面的安全解决方案 , 对用户的身份进行认证, 以及验证每一个用户所具有的的权限, 根据用户的权限限制用户的操作。
Mybatis 是一款优秀的持久层框架 , 支持自定义 SQL 以及各种高级映射 , 与 JPA 的自动生成 SQL 相比, 它更加灵活, 本例使用 Mybatis 存储用户的身份和权限, 通过 Security 获取用户信息, 对用户的权限和操作进行管理。
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
username: root
password: roof
url: jdbc:mysql://localhost:3306/security?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&autoReconnect=true
# 配置前端Thymeleaf模板引擎
thymeleaf:
# 打包末尾无/
prefix: classpath:/templates/
check-template-location: true
suffix: .html
encoding: UTF-8
servlet:
content-type: text/html
mode: HTML5
# 禁止后实现前端热部署
cache: false
# 集成Mybatis
mybatis:
# Mybatis映射
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.hly.springBootSecurityMybatis.entity
# 端口设置
server:
port: 8081
@Configuration
@EnableWebSecurity//开启WebSecurity功能
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启方法上的保护
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
UserDetailsService userService(){
return new UserService();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//从数据库中获取用户认证信息
auth.userDetailsService(userService());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//不需要验证的资源
.antMatchers("/css/**", "/index").permitAll()
//需要验证,角色为Role
.antMatchers("/article/**").hasAnyRole("ADMIN","STUDENT","TEACHER")
.antMatchers("/admin/**").hasAnyRole("ADMIN","STUDENT","TEACHER")
.and()
//表单的登录地址和失败地址
.formLogin().loginPage("/login").failureForwardUrl("/loginError")
.and()
//异常处理界面
.exceptionHandling().accessDeniedPage("/401");
http.logout().logoutSuccessUrl("/");
}
}
@Controller
public class ArticleController {
@Autowired
ArticleService articleService;
/**
* 查看文章列表
* @param model
* @return
*/
@RequestMapping("/article")
public ModelAndView articleList(Model model){
List list = articleService.getArticles();
model.addAttribute("articlesList",list);
return new ModelAndView("article/list","articleModel",model);
}
/**
* 给方法设置权限,没有ADMIN权限的用户不能删除文章
* @param id
* @param model
* @return
*/
@PreAuthorize("hasAnyAuthority('ROLE_ADMIN')")
@GetMapping(value = "/article/{id}/deletion")
public ModelAndView delete(@PathVariable("id")int id,Model model){
articleService.deleteArticle(id);
model.addAttribute("articlesList",articleService.getArticles());
return new ModelAndView("article/list","articleModel",model);
}
}
@Controller
public class LoginController {
@RequestMapping("/")
public String root(){
return "redirect:/index";
}
@RequestMapping("index")
public String index(){
return "index";
}
//@RequestMapping将接收Get,Post,Head,Options等所有的请求方式
@RequestMapping(value = "/login")
public String login(){
return "login";
}
@RequestMapping("/loginError")
public String loginError(ModelAndView modelAndView){
modelAndView.addObject("loginError",true);
return "login";
}
@RequestMapping("/admin")
public String admin(){
return "admin/admin";
}
//@RequestMapping(method = RequestMethod.GET)的缩写
@GetMapping("401")
public String error(){
return "401";
}
@GetMapping("/logout")
public String logout(){
return "/";
}
}
@Repository
public interface UserDao {
//通过用户名查询用户
public User findUserByUsername(String username);
}
Article
public class Article {
private int id;
private String title;
private String content;
public Article() {
}
public Article(int id, String title, String content) {
this.id = id;
this.title = title;
this.content = content;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "Article{" +
"id=" + id +
", title='" + title + '\'' +
", content='" + content + '\'' +
'}';
}
}
Role
public class Role implements GrantedAuthority {
private int id;
private String name;
@Override
public String getAuthority() {
return name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
User
public class User implements UserDetails, Serializable {
private int id;
private String username;
private String password;
private List roles;
@Override
public Collection extends GrantedAuthority> getAuthorities() {
return roles;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
@Service
public class ArticleServiceImpl implements ArticleService {
private List list = new ArrayList<>();
public ArticleServiceImpl() {
list.add(new Article(1,"java","java从入门到搬砖"));
list.add(new Article(2,"SQL","SQL从删库到跑路"));
}
@Override
public List getArticles() {
return list;
}
@Override
public void deleteArticle(int id) {
Iterator iter = list.iterator();
while(iter.hasNext()){
Article article = (Article)iter.next();
if(article.getId()==id){
iter.remove();
}
}
}
}
public interface ArticleService {
List getArticles();
void deleteArticle(int id);
}
@Service
public class UserService implements UserDetailsService {
@Autowired
private UserDao userDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.err.println(userDao.findUserByUsername(username));
return userDao.findUserByUsername(username);
}
}
admin.html
Title
拥有权限才能访问该页面
list.html
list
文章管理,ADMIN角色才能删除
文章编号
文章标题
文章内容
删除
index.html
Title
首页任何角色都能访问
登录用户:
用户角色:
login.html
Title
登录页面
用户名或密码错误
/*
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(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES ('1', 'ROLE_ADMIN');
INSERT INTO `role` VALUES ('2', 'ROLE_TEACHER');
INSERT INTO `role` VALUES ('3', 'ROLE_STUDENT');
INSERT INTO `role` VALUES ('4', 'ROLE_COUNSELOR');
-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UK_USERNAME` (`username`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'admin', '$2a$10$NmtmORbN/ATToou17gvjl.CUu1yTNxxRjsO2GOJUbJFsWd21pYmFi');
INSERT INTO `user` VALUES ('2', 'js', '$2a$10$NmtmORbN/ATToou17gvjl.CUu1yTNxxRjsO2GOJUbJFsWd21pYmFi');
INSERT INTO `user` VALUES ('3', 'xs', '$2a$10$NmtmORbN/ATToou17gvjl.CUu1yTNxxRjsO2GOJUbJFsWd21pYmFi');
INSERT INTO `user` VALUES ('4', 'fdy', '$2a$10$NmtmORbN/ATToou17gvjl.CUu1yTNxxRjsO2GOJUbJFsWd21pYmFi');
-- ----------------------------
-- Table structure for `user_role`
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`user_id` int(11) NOT NULL,
`role_id` int(11) NOT NULL,
KEY `FKuser_id` (`role_id`),
KEY `FKrole_id` (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT INTO `user_role` VALUES ('1', '1');
INSERT INTO `user_role` VALUES ('2', '2');
INSERT INTO `user_role` VALUES ('3', '3');
INSERT INTO `user_role` VALUES ('4', '4');
我们在 security 里配置了 Index 页面不需要验证即可访问,访问
http://localhost:8081/index
在没有登录之前,通过浏览器访问其他任何页面,都会跳转到登录界面。
登录之后即可进入管理页面,这里的加密密码都是123,账号请看数据库。
在管理文章里面,我们在 controller 层配置了只有 ADMIN 用户才能删除,其他用户如果点击删除将会提示没有权限。
我的 Github:Github
个人网站: 天狼星的博客
源代码:https://github.com/huangliangyun/Spring-Boot-2.X
QQ交流群:865061230
参考<<深入理解SpringCloud微服务构建>>