SpringBoot 2.0 | Security+Mybatis 权限认证

版权声明:自由转载-非商用-保持署名,听说看完点赞的人都挺帅。QQ交流群:865061230 https://blog.csdn.net/Sirius_hly/article/details/84584537

1.简介

Spring Security 是 Spring 家族的一个安全框架, 提供了全面的安全解决方案 , 对用户的身份进行认证, 以及验证每一个用户所具有的的权限, 根据用户的权限限制用户的操作。

Mybatis 是一款优秀的持久层框架 , 支持自定义 SQL 以及各种高级映射 , 与 JPA 的自动生成 SQL 相比, 它更加灵活, 本例使用 Mybatis 存储用户的身份和权限, 通过 Security 获取用户信息, 对用户的权限和操作进行管理。

2.实现代码

1.项目配置

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

2.Security 配置

@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("/");
    }
}

3.controller 层

@Controller
public class ArticleController {

    @Autowired
    ArticleService articleService;
    /**
     * 查看文章列表
     * @param model
     * @return
     */
    @RequestMapping("/article")
    public ModelAndView articleList(Model model){
        List<Article> 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 "/";
    }
}

4.dao 层

@Repository
public interface UserDao {

    //通过用户名查询用户
    public User findUserByUsername(String username);
}

5. entity

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<Role> 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;
    }
}

6.service层

@Service
public class ArticleServiceImpl implements ArticleService {

    private List<Article> list = new ArrayList<>();

    public ArticleServiceImpl() {
        list.add(new Article(1,"java","java从入门到搬砖"));
        list.add(new Article(2,"SQL","SQL从删库到跑路"));
       
    }
    @Override
    public List<Article> 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<Article> 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);
    }
}

7.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.hly.springBootSecurityMybatis.dao.UserDao">

    <resultMap id="userMap" type="User">
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <result property="password" column="password"/>
        <collection property="roles" ofType="Role">
            <result property="name" column="name"/>
        </collection>
    </resultMap>

    <select id="findUserByUsername" parameterType="string" resultMap="userMap">
        SELECT u.*,r.name FROM user u
        LEFT JOIN user_role ur ON u.id = ur.user_id
        LEFT JOIN role r ON ur.role_id = r.id
        WHERE username = #{username}
    </select>
    
</mapper>

8.前端页面

admin.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/xhtml" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>拥有权限才能访问该页面</h3>
<p><a href="../../templates/article/list.html" th:href="@{/article}" >管理文章</a></p>
<p><a href="../../templates/index.html" th:href="@{/index}" >返回首页</a></p>
<div th:substituteby="index::user"></div>
</body>
</html>

list.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
    <meta charset="UTF-8">
    <title>list</title>
</head>
<body>
<h3>文章管理,ADMIN角色才能删除</h3>
<table>
    <tr>
        <td><b>文章编号</b></td>
        <td><b>文章标题</b></td>
        <td><b>文章内容</b></td>
    </tr>
    <tr th:each="article:${articlesList}">
        <td th:text="${article.id}"></td>
        <td th:text="${article.title}"></td>
        <td th:text="${article.content}"></td>
        <td><a href="" th:href="@{'/article/'+${article.id}+'/deletion'}">删除</a></td>
    </tr>
</table>
<div th:substituteby="index::user"></div>
</body>
</html>

index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/xhtml" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>首页任何角色都能访问</h3>
<p><a href="../templates/admin/admin.html" th:href="@{/admin}">查看被保护界面: /admin</a></p>

<div th:fragment="user" sec:authorize="isAuthenticated()">
    登录用户:<span sec:authentication="name"></span>
    用户角色:<span sec:authentication="principal.authorities"></span>
    <div>
        <form th:action="@{/logout}" method="post">
            <input type="submit" value="退出">
        </form>
    </div>
</div>

</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/xhtml" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h2>登录页面</h2>
<p th:if="${loginError}">用户名或密码错误</p>
<form th:action="@{/login}" method="post">
    <label for="username">用户名</label>
    <input type="text" id="username" name="username" autofocus="autofocus" autocomplete="new-text">
    <label for="password">密码</label>
    <input type="password" id="password" name="password" autocomplete="new-password">
    <input type="submit" value="login">
    <p><a href="/index" th:href="@{/index}">返回首页</a></p>

</form>

</body>
</html>

9.数据库如下

/*
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');

10.整个项目结构

在这里插入图片描述

3.测试结果

我们在 security 里配置了 Index 页面不需要验证即可访问,访问
http://localhost:8081/index

扫描二维码关注公众号,回复: 4290023 查看本文章

在这里插入图片描述

在没有登录之前,通过浏览器访问其他任何页面,都会跳转到登录界面。
在这里插入图片描述
登录之后即可进入管理页面,这里的加密密码都是123,账号请看数据库。
在这里插入图片描述
在管理文章里面,我们在 controller 层配置了只有 ADMIN 用户才能删除,其他用户如果点击删除将会提示没有权限。
在这里插入图片描述

源代码:https://github.com/huangliangyun/Spring-Boot-2.X
QQ交流群:865061230
参考<<深入理解SpringCloud微服务构建>>

猜你喜欢

转载自blog.csdn.net/Sirius_hly/article/details/84584537