Spring Boot中使用Spring Security自定义验证

因为网上关于这个springboot+security自定义验证有好多写的有点杂乱,在仿写的过程中总是出现莫名其妙的bug,所以专门写一篇最基础的出来。

本篇还是使用熟悉的springboot+mybatis+thymeleaf来搭最基础的架构,当然不用数据库也是可以的,自己在逻辑实现类新建一个对象测试就好了。


一、新建数据库
这里写图片描述

二、打开IDEA新建项目,勾这三个

这里写图片描述

这里写图片描述

三、项目架构

这里写图片描述

四、各部分的实现

1、pom.xml下添加mybatis和mysql的依赖,以及对xml路径的支持

<!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.21</version>
        </dependency>
<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>

        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>

2、application.properties文件下添加数据库的信息

spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
mybatis.mapperLocation=classpath*:com/**/*Mapper.xml

3、持久层mapper包下

创建UserMapper接口

扫描二维码关注公众号,回复: 3475606 查看本文章
package com.mapper;

import com.model.User;
import org.apache.ibatis.annotations.Mapper;

/**
 * Created by Administrator on 2016/12/9.
 */
@Mapper
public interface UserMapper {
    User selectById(String id);
    User selectByUsername(String username);
}

同包下创建UserMapper.xml

<?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.mapper.UserMapper" >
  <resultMap id="BaseResultMap" type="com.model.User" >
    <id column="id" property="id" jdbcType="VARCHAR" />
    <result column="username" property="username" jdbcType="VARCHAR" />
    <result column="password" property="password" jdbcType="VARCHAR" />
    <result column="role" property="role" jdbcType="VARCHAR" />
  </resultMap>

  <select id="selectById" resultMap="BaseResultMap" >
    select id, username,password,role
    from user
    where id = #{id, jdbcType=VARCHAR}
  </select>
  <select id="selectByUsername" resultMap="BaseResultMap" >
    select id, username,password,role
    from user
    where username = #{username, jdbcType=VARCHAR}
  </select>

</mapper>

4、实体层model创建实体类User,继承UserDetails

package com.model;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;

/**
 * Created by Administrator on 2016/12/9.
 */
public class User implements Serializable, UserDetails  {
    private String id;
    private String username;
    private String password;
    private String role;

    public User(){}

    public User(String username, String password, String  role){

        this.setUsername(username);
        this.setPassword(password);
        this.setRole(role);

    }
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

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

    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return Arrays.asList(new SimpleGrantedAuthority(getRole()));
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }
}

5、安全层security包下创建SecurityConfig类,处理登录权限等等。

package com.security;

import com.service.UserService;
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;

@Configuration
//@EnableWebSecurity: 禁用Boot的默认Security配置,配合@Configuration启用自定义配置
// (需要扩展WebSecurityConfigurerAdapter)
@EnableWebSecurity
//@EnableGlobalMethodSecurity(prePostEnabled = true): 启用Security注解,
// 例如最常用的@PreAuthorize
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService userService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {
        // Configure spring security's authenticationManager with custom
        // user details service
        auth.userDetailsService(this.userService);
    }

    @Override
    //configure(HttpSecurity): Request层面的配置,对应XML Configuration中的<http>元素
    //定义URL路径应该受到保护,哪些不应该
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                // 例如以下代码指定了/和/index不需要任何认证就可以访问,其他的路径都必须通过身份验证。
                .antMatchers("/", "/index").permitAll()
                .anyRequest().authenticated()
                .and()
                //通过formLogin()定义当需要用户登录时候,转到的登录页面。
                .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
                //注销
                .logout()
                .permitAll();
        //关闭csrf 防止循环定向
        http.csrf().disable();
    }


}

6、业务逻辑层service创建UserService类

package com.service;

import com.mapper.UserMapper;
import com.model.User;
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;

/**
 * Created by Administrator on 2016/12/13.
 */
@Service
public class UserService implements UserDetailsService {
    @Autowired
    private UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.selectByUsername(username);

        if( user == null ){
            throw new UsernameNotFoundException(String.format("User with username=%s was not found", username));
        }

        return user;
    }
}

7、网络层(我比较喜欢叫控制层)controller下创建HelloController类
这里映射到resources目录下的templates的html页面。

package com.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class HelloController {

    @RequestMapping("/")
    public String index() {
        return "index";
    }

    @RequestMapping("/hello")
    public String hello(){
        return "hello";
    }

    @RequestMapping(value = "/login")
    public String login() {
        return "login";
    }

}

8、在resources目录下的templates创建3个html(默认页,登录页跟登录后才能进入的页面)

hello.xml

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
    <title>Hello World!</title>
</head>
<body>
<h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
<form th:action="@{/logout}" method="post">
    <input type="submit" value="注销"/>
</form>
</body>
</html>

index.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
    <title>Hello World!</title>
</head>
<body>
<h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
<form th:action="@{/logout}" method="post">
    <input type="submit" value="注销"/>
</form>
</body>
</html>

login.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
    <title>Hello World!</title>
</head>
<body>
<h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
<form th:action="@{/logout}" method="post">
    <input type="submit" value="注销"/>
</form>
</body>
</html>

五、做完以上,就能实现最基础的web安全控制了,当然你还可以加url的权限控制,这些网上可搜到很多资料而且不会乱。我这里展示一下。

1、数据库中加入测试数据

这里写图片描述

这里要注意的是role必须为ROLE_xx形式,不然security识别不出来。

2、在controller类中加入以下控制方法

@RequestMapping(value = "/helloadmin")
    //对应数据库中role为“ROLE_admin”
    @PreAuthorize("hasAnyRole('admin')")
    public String helloAdmin(){
        return "helloadmin";
    }

    @RequestMapping(value = "/hellouser")
    //对应数据库中role为“ROLE_admin”与“ROLE_user”
    @PreAuthorize("hasAnyRole('admin', 'user')")
    public String helloUser(){
        return "hellouser";
    }

3、然后你自己新增俩个测试html(hellouser.html与helloadmin.html),发现以用户名为user登录是进不去helloadmin的。

这里写图片描述

猜你喜欢

转载自blog.csdn.net/h295928126/article/details/53612358