• SpringBoot + Security实现权限控制


    网上找了好几个,因为各种原因不太行,下面这个亲测可行

    参考:https://blog.csdn.net/u012702547/article/details/54319508

    基于SpringBoot + JPA

    安全框架:Security5

    页面:Thymeleaf + BootStrap

    工程目录结构:

     引入依赖包

    pom.xml

    <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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.zit</groupId>
      <artifactId>Hello</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>jar</packaging>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      </properties>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.0.RELEASE</version>
        </parent>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            
            <dependency>
                   <groupId>org.springframework.boot</groupId>
                   <artifactId>spring-boot-starter-data-jpa</artifactId>
             </dependency>
             
             <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
            
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
             
             <dependency>
                <groupId>org.thymeleaf.extras</groupId>
                <artifactId>thymeleaf-extras-springsecurity4</artifactId>
            </dependency>
             
             <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.40</version>
            </dependency>
            
        </dependencies>
        
        <repositories>
            <repository>
                <id>spring-snapshots</id>
                <name>Spring Snapshots</name>
                <url>https://repo.spring.io/libs-snapshot</url>
                <snapshots>
                    <enabled>true</enabled>
                </snapshots>
            </repository>
        </repositories>
    
    </project>

     配置文件

    application.properties

    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
    spring.datasource.username=root
    spring.datasource.password=
    logging.level.org.springframework.security=info
    spring.thymeleaf.cache=false
    spring.jpa.hibernate.ddl-auto=update
    spring.jpa.show-sql=true
    spring.jackson.serialization.indent_output=true
    
    spring.thymeleaf.cache=false
     

    1、实体类

    (1)用户

    package com.zit;
    
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.userdetails.UserDetails;
    
    import javax.persistence.*;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    
    /**
     * 
     */
    @Entity
    public class SysUser implements UserDetails {
        @Id
        @GeneratedValue
        private Long id;
        private String username;
        private String password;
    
        @ManyToMany(cascade = {CascadeType.REFRESH},fetch = FetchType.EAGER)
        private List<SysRole> roles;
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public List<SysRole> getRoles() {
            return roles;
        }
    
        public void setRoles(List<SysRole> roles) {
            this.roles = roles;
        }
    
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            List<GrantedAuthority> auths = new ArrayList<>();
            List<SysRole> roles = this.getRoles();
            for (SysRole role : roles) {
                auths.add(new SimpleGrantedAuthority(role.getName()));
            }
            return auths;
        }
    
        @Override
        public String getPassword() {
            return this.password;
        }
    
        @Override
        public String getUsername() {
            return this.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;
        }
    }

    (2)角色

    package com.zit;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    
    /**
     * 
     */
    @Entity
    public class SysRole {
        @Id
        @GeneratedValue
        private Long id;
        private String name;
    
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }

    2、JPA访问数据库

    package com.zit;
    
    import org.springframework.data.jpa.repository.JpaRepository;
    
    public interface SysUserRepository extends JpaRepository<SysUser, Long> {
        SysUser findByUsername(String username);
    }

    3、控制器

    (1)控制器给页面传值的对象

    package com.zit;
    
    /**
     * 传递在页面上的消息
     */
    public class Msg {
        private String title;
        private String content;
        private String extraInfo;
    
        public Msg() {
        }
    
        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;
        }
    
        public String getExtraInfo() {
            return extraInfo;
        }
    
        public void setExtraInfo(String extraInfo) {
            this.extraInfo = extraInfo;
        }
    
        public Msg(String title, String content, String extraInfo) {
            this.title = title;
            this.content = content;
            this.extraInfo = extraInfo;
        }
    }

    (2)控制类

    package com.zit;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class HomeController {
        @RequestMapping("/")
        public String index(Model model) {
            Msg msg = new Msg("测试标题", "测试内容", "额外信息,只对管理员显示");
            model.addAttribute("msg", msg);
            return "index";
        }
    }

    4、自定义UserDetailsService

    package com.zit;
    
    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;
    
    
    public class CustomUserService implements UserDetailsService {
        @Autowired
        SysUserRepository userRepository;
        @Override
        public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
            SysUser user = userRepository.findByUsername(s);
            if (user == null) {
                throw new UsernameNotFoundException("用户名不存在");
            }
            System.out.println("s:"+s);
            System.out.println("username:"+user.getUsername()+";password:"+user.getPassword());
            return user;
        }
    }

    5、SpringMVC配置

    package com.zit;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    
    @Configuration
    public class WebMvcConfig extends WebMvcConfigurerAdapter {
        @Override
        public void addViewControllers(ViewControllerRegistry registry) {
            registry.addViewController("/login").setViewName("login");
        }
    }

    当用户访问login时跳转到login.html页面

    6、配置Spring Security

    由于Spring Security5必须自定义密码加密,所以建立一个自定义密码加密类

    (1)MyPasswordEncoder.java

    package com.zit;
    
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    public class MyPasswordEncoder implements PasswordEncoder {
    
        @Override
        public String encode(CharSequence arg0) {
            return arg0.toString();
        }
    
        @Override
        public boolean matches(CharSequence arg0, String arg1) {
            return arg1.equals(arg0.toString());
        }
    
    }

    (2)Security配置

    package com.zit;
    
    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.core.userdetails.UserDetailsService;
    
    
    @Configuration
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Bean
        UserDetailsService customUserService() {
            return new CustomUserService();
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(customUserService())
            .passwordEncoder(new MyPasswordEncoder());
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                //security允许页面加载css文件夹下的静态资源
                .antMatchers("/css/**").permitAll()
                    .anyRequest().authenticated()
                    .and().formLogin().loginPage("/login").failureUrl("/login?error").permitAll()
                    .and()
                    .logout()
                    .permitAll();
        }
    }

    1.首先当我们要自定义Spring Security的时候我们需要继承自WebSecurityConfigurerAdapter来完成,相关配置重写对应 方法即可。 
    2.我们在这里注册CustomUserService的Bean,然后通过重写configure方法添加我们自定义的认证方式。 
    3.在configure(HttpSecurity http)方法中,我们设置了登录页面,而且登录页面任何人都可以访问,然后设置了登录失败地址,也设置了注销请求,注销请求也是任何人都可以访问的。 
    4.permitAll表示该请求任何人都可以访问,.anyRequest().authenticated(),表示其他的请求都必须要有权限认证。 

    7、静态资源

    (1)CSS

    下载bootstrap包,取其bootstrap.min.css

    另,自己写一个signin.css,如下:

    body {
        padding-top: 40px;
        padding-bottom: 40px;
        background-color: #eee;
    }
    
    .form-signin {
        max- 330px;
        padding: 15px;
        margin: 0 auto;
    }
    .form-signin .form-signin-heading,
    .form-signin .checkbox {
        margin-bottom: 10px;
    }
    .form-signin .checkbox {
        font-weight: normal;
    }
    .form-signin .form-control {
        position: relative;
        height: auto;
        -webkit-box-sizing: border-box;
        -moz-box-sizing: border-box;
        box-sizing: border-box;
        padding: 10px;
        font-size: 16px;
    }
    .form-signin .form-control:focus {
        z-index: 2;
    }
    .form-signin input[type="email"] {
        margin-bottom: -1px;
        border-bottom-right-radius: 0;
        border-bottom-left-radius: 0;
    }
    .form-signin input[type="password"] {
        margin-bottom: 10px;
        border-top-left-radius: 0;
        border-top-right-radius: 0;
    }

    (2)HTML

    login.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8"/>
        <title>登录</title>
        <link rel="stylesheet" th:href="@{css/bootstrap.min.css}"/>
        <link rel="stylesheet" th:href="@{css/signin.css}"/>
        <style type="text/css">
            body {
                padding-top: 50px;
            }
            .starter-template {
                padding: 40px 15px;
                text-align: center;
            }
        </style>
    </head>
    <body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <a class="navbar-brand" href="#">Spring Security演示</a>
            </div>
            <div id="navbar" class="collapse navbar-collapse">
                <ul class="nav navbar-nav">
                    <li><a th:href="@{/}">首页</a></li>
                    <li><a th:href="@{http://www.baidu.com}">百度</a></li>
                </ul>
            </div>
        </div>
    </nav>
    <div class="container">
        <div class="starter-template">
            <p th:if="${param.logout}" class="bg-warning">已注销</p>
            <p th:if="${param.error}" class="bg-danger">有错误,请重试</p>
            <h2>使用账号密码登录</h2>
            <form class="form-signin" role="form" name="form" th:action="@{/login}" action="/login" method="post">
                <div class="form-group">
                    <label for="username">账号</label>
                    <input type="text" class="form-control" name="username" value="" placeholder="账号"/>
                </div>
                <div class="form-group">
                    <label for="password">密码</label>
                    <input type="password" class="form-control" name="password" placeholder="密码"/>
                </div>
                <input type="submit" id="login" value="Login" class="btn btn-primary"/>
            </form>
        </div>
    </div>
    
    
    </body>
    </html>

    index.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org"
          xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
    <head>
        <meta charset="UTF-8"/>
        <title sec:authentication="name"></title>
        <link rel="stylesheet" th:href="@{css/bootstrap.min.css}"/>
        <style type="text/css">
            body {
                padding-top: 50px;
            }
            .starter-template {
                padding: 40px 15px;
                text-align: center;
            }
        </style>
    </head>
    <body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <a class="navbar-brand" href="#">Spring Security演示</a>
            </div>
            <div id="navbar" class="collapse navbar-collapse">
                <ul class="nav navbar-nav">
                    <li><a th:href="@{/}">首页</a></li>
                    <li><a th:href="@{http://www.baidu.com}">百度</a></li>
                </ul>
            </div>
        </div>
    </nav>
    <div class="container">
        <div class="starter-template">
            <h1 th:text="${msg.title}"></h1>
            <p class="bg-primary" th:text="${msg.content}"></p>
            <div sec:authorize="hasRole('ROLE_ADMIN')">
                <p class="bg-info" th:text="${msg.extraInfo}"></p>
            </div>
            <div sec:authorize="hasRole('ROLE_USER')">
                <p class="bg-info">无更多显示信息</p>
            </div>
            <form th:action="@{/logout}" method="post">
                <input type="submit" class="btn btn-primary" value="注销"/>
            </form>
        </div>
    </div>
    </body>
    </html>
  • 相关阅读:
    Python服务Debian打包新思路
    小议Python3的原生协程机制
    推送公司今日菜单内容到手机
    Python包管理工具小结
    PAT 1068. 万绿丛中一点红
    PAT 1067. 试密码
    PAT 1066. 图像过滤
    PAT 1065. 单身狗
    PAT 1064. 朋友数
    PAT 1063. 计算谱半径
  • 原文地址:https://www.cnblogs.com/Donnnnnn/p/8716247.html
Copyright © 2020-2023  润新知