SpringBoot 之集成Security

本文详细介绍SpringBoot与SpringSecurity的集成步骤,涵盖依赖导入、配置定制、控制器编写及界面展示,深入解析权限控制、数据库用户认证、Session管理与用户信息获取等关键环节。

快速入门

导入依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.3.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
    
<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>

配置WebSecurityConfigurerAdapter

新建SecurityConfig类,作为配置类。

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;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@EnableWebSecurity
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) // 注解开启了方法级别的保护
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService()).passwordEncoder(new BCryptPasswordEncoder());
    }

    @Bean
    public UserDetailsService userDetailsService() {
        // 在内存中存放用户信息
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        // 在内存中创建了 一个认证用户的信息,yq, 密码为123456, 有ROLE_USER的角色。
        manager.createUser(
                User.withUsername("yq").password(new BCryptPasswordEncoder()
                        .encode("123456")).roles("USER").build());
        manager.createUser(
                User.withUsername("admin").password(new BCryptPasswordEncoder()
                        .encode("123456")).roles("ADMIN").build());
        return manager;
    }

    // 配置如何验证身份
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // 启用基于 HttpServletRequest 的访问限制,开始配置哪些URL需要被保护、哪些不需要被保护
                .authorizeRequests()
                // 允许未登陆用户访问的资源
                .antMatchers( "/favicon.ico","/css/**","/index","/js/**","/images/**").permitAll()
                // /user/**的这个资源需要有ROLE_USER的这个角色才能访问,不然就会提示拒绝访问
                .antMatchers("/user/**").hasRole("USER")
                .antMatchers("/blogs/**").hasRole("ADMIN")
                // 任何尚未匹配的URL只需要验证用户即可访问
                .anyRequest().authenticated()
                .and()
                // 设置登陆相关的配置
                .formLogin()
                // 登陆界面页面跳转URL
                .loginPage("/login")
                // 登陆失败页面跳转URL
                .failureUrl("/login-error")
                // 登陆成功跳转的页面,可以不设置,默认跳转到需要登陆之前的页面
//                .defaultSuccessUrl("/index")
                // permitAll表示不需要验证 登录页面,登录失败页面
                .permitAll()
                .and()
                // 权限拒绝页面跳转URL
                .exceptionHandling().accessDeniedPage("/401");
        // 注销登录成功,重定向到首页
        http.logout().logoutSuccessUrl("/");
    }
}

编写控制器

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MainController {

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

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

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

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

    @RequestMapping("/login-error")
    public String loginError(Model model) {
        model.addAttribute("loginError", true);
        return "login";
    }
    @GetMapping("/401")
    public String accesssDenied() {
        return "401";
    }
}

配置文件application.yml

spring:
  thymeleaf:
    mode: HTML5
    encoding: UTF-8
    cache: false

编写相关界面

在这里插入图片描述
登录界面login.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Login page</title>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
</head>
<body>
<h1>Login page</h1>
<p>User角色用户: yq / 123456</p>
<p>Admin角色用户: admin / 123456</p>
<p th:if="${loginError}" class="error">用户名或密码错误</p>
<form th:action="@{/login}" method="post">
    <label for="username">用户名</label>:
    <input type="text" id="username" name="username" autofocus="autofocus" /> <br />
    <label for="password">密码</label>:
    <input type="password" id="password" name="password" /> <br />
    <input type="submit" value="登录" />
</form>
<p><a href="/index" th:href="@{/index}">返回首页</a></p>
</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-springsecurity4">
<head>
    <title>Hello Spring Security</title>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
</head>
<body>

<h1>Hello Spring Security</h1>
<p>这个界面没有受保护,你可以进已被保护的界面.</p>

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

<ul>
    <li>点击<a href="/user/index" th:href="@{/user/index}">去/user/index保护的界面</a></li>
</ul>
</body>
</html>

权限不够显示的界面401.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"
      xmlns:th="http://www.thymeleaf.org">

<body>
<div >
    <div th:substituteby="index::logout"></div>
    <div >
        <h2> 权限不够</h2>
    </div>
    <div sec:authorize="isAuthenticated()">
        <p>已有用户登录</p>
        <p>用户: <span sec:authentication="name"></span></p>
        <p>角色: <span sec:authentication="principal.authorities"></span></p>
    </div>
    <div sec:authorize="isAnonymous()">
        <p>未有用户登录</p>
    </div>
    <p>
        拒绝访问!
    </p>
</div>

</body>
</html>

用户首页/user/index.html界面,该资源被Spring Security保护,只有拥有ROLE_USER角色的用户才能够访问。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Hello Spring Security</title>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
</head>
<body>
<div th:substituteby="index::logout"></div>
<h1>这个界面是被保护的界面</h1>
<p><a href="/index" th:href="@{/index}">返回首页</a></p>
<p><a  href="/blogs" th:href="@{/blogs}">管理博客</a></p>
</body>
</html>

main.css

body {
    font-family: sans;
    font-size: 1em;
}
p.error {
    font-weight: bold;
    color: red;
}

div.logout {
    float: right;
}

启动测试

http://127.0.0.1:8080/index
在这里插入图片描述
单击/user/index保护的界面,由于/user/index界面需要ROLE_USER权限,由于未登录,会被重定向到登录界面/login.html
在这里插入图片描述
用具有ROLE_USER权限角色的用户登录,用户名:yq ,密码:123456。登录成功,界面会被重定向到http://localhost:8080/user/index界面,注意该界面是具有ROLE_USER权限角色的用户才具有访问权限。
在这里插入图片描述
然后登出yq用户,用具有ROLE_ADMIN权限角色的用户登录,会被重定向到权限不足的页面。
在这里插入图片描述

方法级别的安全支持

@EnableGlobalMethodSecurity(prePostEnabled = true)注解可以开启方法级别的保护

  • prePostEnabled:Spring Security 的 Pre 和 Post 注解是否可用。
  • @PreAuthorize注解会在进入方法前进行权限验证
  • @PostAuthorize注解在方法执行后再进行权限验证

具有ROLE_ADMIN角色的用户才能访问
@PreAuthorize(“hasAuthority(‘ROLE_ADMIN’)”)
也可以写为
@PreAuthorize(“hasRole(‘ROLE_ADMIN’)”)
这二者是等价的。

加多个权限角色
@PreAuthorize(“hasAnyRole(‘ROLE_ADMIN’,‘ROLE_USER’)”)
也可以写为
@PreAuthorize(“hasAnyAuthority(‘ROLE_ADMIN’,‘ROLE_USER’)”)
这二者是等价的。

案例编写
1、实体

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Blog {
    private Long id;
    private String name;
    private String content;
}

2、编写Service,模拟一个Dao

import com.example.security.entity.Blog;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

@Service
public class BlogService {

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

    public BlogService(){
        list.add(new Blog(1L,"spring in action", "good!"));
        list.add(new Blog(2L,"spring cloud in action", "nice!"));
        list.add(new Blog(3L,"Hadoop in action", "nice!"));
        list.add(new Blog(4L,"Yarn in action", "nice!"));
        list.add(new Blog(5L,"Java in action", "nice!"));
    }

    public List<Blog> getBlogs() {
        return list;
    }

    public void deleteBlog(long id) {
        Iterator iter = list.iterator();
        while(iter.hasNext()) {
            Blog blog= (Blog) iter.next();
            if (blog.getId()==id){
                iter.remove();
            }
        }
    }
}

3、编写Controller
只有ROLE_ADMIN角色的用户才能删除一条数据。

import com.example.security.entity.Blog;
import com.example.security.service.BlogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import java.util.List;

@RestController
@RequestMapping("/blogs")
public class BlogController {

    @Autowired
    BlogService blogService;

    @GetMapping
    public ModelAndView list(Model model) {
        List<Blog> list =blogService.getBlogs();
        model.addAttribute("blogsList", list);
        return new ModelAndView("blogs/list", "blogModel", model);
    }

    @PreAuthorize("hasAnyAuthority('ROLE_ADMIN')")
    @GetMapping(value = "/{id}/deletion")
    public ModelAndView delete(@PathVariable("id") Long id, Model model) {
        blogService.deleteBlog(id);
        model.addAttribute("blogsList", blogService.getBlogs());
        return new ModelAndView("blogs/list", "blogModel", model);
    }
}

博客清单页面/blogs/list.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div>
    <table >
        <thead>
        <tr>
            <td>博客编号</td>
            <td>博客名称</td>
            <td>博客描述</td>
        </tr>
        </thead>
        <tbody>
        <tr th:each="blog: ${blogModel.blogsList}">
            <td th:text="${blog.id}"></td>
            <td th:text="${blog.name}"></td>
            <td th:text="${blog.content}"></td>
            <td>
                <div >
                    <a th:href="@{'/blogs/' + ${blog.id}+'/deletion'}">
                        删除
                    </a>
                </div>
            </td>
        </tr>
        </tbody>
    </table>
</div>
</body>
</html>

4、启动测试
使用yq用户登陆,可以访问博客清单页面,删除会提示权限不足。
在这里插入图片描述
使用admin用户登陆,可以正常删除博客。
在这里插入图片描述

从数据库中读取用户的认证信息

在快速入门中,采用了从内存中配置用户信息,包括用户名、密码、用户的角色权限信息。如果用户数量非常多时,这种方式显然是不可行的 。
下面编写如何从数据库中读取用户和用户的角色权限信息,采用的数据库为MySQL,ORM 框架为 JPA 。

1、导入依赖

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.42</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

2、配置文件application.yml

spring:
  thymeleaf:
    mode: HTML5
    encoding: UTF-8
    cache: false

  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
    username: root
    password: 123456

  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true

3、创建实体
User 类实现了 UserDetails 接口,该接口是实现 Spring Security 认证信息的核心接口。其中,getUsemame()方法为 UserDetails 接口的方法,这个方法不一定返回usemame ,也可以是其他的用户信息,例如:手机号码、邮箱地址等。 getAuthorities()方法返回的是该用设置的权限信息,在本例中,从数据库中读取该用户的所有角色信息,权限信息也可以是用户的其他信息,不一定是角色信息。另外需要读取密码,最后几个方法一般情况下都返回 true ,也可以根据自己的需求进行业务判断。

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

import javax.persistence.*;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;

@Entity
public class User implements UserDetails, Serializable {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

	@Column(nullable = false,  unique = true)
	private String username;

	@Column
	private String password;

	@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
		inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"))
	private List<Role> authorities;

	public User() {
	}

	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		return authorities;
	}

	public void setAuthorities(List<Role> authorities) {
		this.authorities = authorities;
	}

	@Override
	public String getUsername() {
		return username;
	}

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

	@Override
	public String getPassword() {
		return password;
	}

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

	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	@Override
	public boolean isEnabled() {
		return true;
	}
}

Role 类实现了 GrantedAuthority 接口,并重写了其 getAuthority() 方法 。权限点可 以为任何字符串,不一定是角色名的字符串,关键是 getAuthority() 方法如何实现。本例的权限点是从数据库读取 Role 表 的 name 字段。

import org.springframework.security.core.GrantedAuthority;
import javax.persistence.*;

@Entity
public class Role implements GrantedAuthority {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

	@Column(nullable = false)
	private String name;

	public Long getId() {
		return id;
	}

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

	@Override
	public String getAuthority() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return name;
	}
}

4、创建Dao
UserDao 中自定义一个根据 usemame 获取 User 的方法,由于 JPA 已经自动实现了根据 usemame 字段去查找用户的方法,因此不需要额外的工作。

import com.example.security.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserDao extends JpaRepository<User, Long>{
	User findByUsername(String username);
}

5、创建Service
Service 层需要实现 UserDetailsService 接口。

import com.example.security.dao.UserDao;
import com.example.security.entity.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;

@Service
public class UserService implements UserDetailsService {

    @Autowired
    private UserDao userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User userDetails = userRepository.findByUsername(username);
        return userDetails;
    }
}

6、修改SecurityConfig配置类

import com.example.security.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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@EnableWebSecurity
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig2 extends WebSecurityConfigurerAdapter {

    @Autowired
    UserService userService;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(new BCryptPasswordEncoder());
    }
    // 配置如何验证身份代码省略,参考快速入门
}

7、数据库表准备
启动程序后,JPA 会连接数据库,在数据库自动建表。
数据库建表脚本如下:

CREATE TABLE `role`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

INSERT INTO `role` VALUES (1, 'ROLE_USER');
INSERT INTO `role` VALUES (2, 'ROLE_ADMIN');

CREATE TABLE `user`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `UK_sb8bbouer5wak8vyiiy4pf2bx`(`username`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- 密码经过BCryptPasswordEncoder进行加密,解密后是:123456
INSERT INTO `user` VALUES (1, '$2a$10$Ce7vMjN1T/X.nlSAVTxDjeGTAuPdOGxEpMNDCqNwjeJv.BORvgXGS', 'yq');
INSERT INTO `user` VALUES (2, '$2a$10$Ce7vMjN1T/X.nlSAVTxDjeGTAuPdOGxEpMNDCqNwjeJv.BORvgXGS', 'admin');

CREATE TABLE `user_role`  (
  `user_id` bigint(20) NOT NULL,
  `role_id` bigint(20) NOT NULL,
  INDEX `FKa68196081fvovjhkek5m97n3y`(`role_id`) USING BTREE,
  INDEX `FK859n2jvi8ivhui0rl0esws6o`(`user_id`) USING BTREE
) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Fixed;

INSERT INTO `user_role` VALUES (1, 1);
INSERT INTO `user_role` VALUES (2, 2);

8、启动测试
和快速入门的效果是一样的。

Session超时处理

设置为10秒(不设置默认是半小时),即连续10秒不操作就会失效。

server:
  servlet:
    session:
      timeout: 10

等10秒之后,任然可以访问,Session并没有失效。

查看TomcatServletWebServerFactory类源码中设置Session的方法,发现如果你设置的Session过期时间是小于1分钟的,那就是1分钟。
在这里插入图片描述

获取用户信息

通过Bean获取用户

获取当前认证用户(authenticated principal)最简单的方式是通过SecurityContextHolder类的静态方法:

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// 首先检查是否存在认证用户
if (!(authentication instanceof AnonymousAuthenticationToken)) {
    String currentUserName = authentication.getName();
    return currentUserName;
}

在控制器中获取用户

在@Controller 注解的bean里,有额外的选项。Principal 和 Authentication 可以直接作为方法参数,框架会自动赋值。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.security.Principal;

@Controller
public class SecurityController {

    @GetMapping("/getName")
    @ResponseBody
    public String getName(Principal principal){
        return principal.getName();
    }
}    
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class SecurityController {

    @GetMapping("/getName")
    @ResponseBody
    public String getName(Authentication authentication){
        return authentication.getName();
    }
}    

框架为Authentication类赋予了很多的功能。
在这里插入图片描述
通过HttpRequest:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.security.Principal;

@Controller
public class SecurityController {

    @GetMapping("/getName")
    @ResponseBody
    public String getName(HttpServletRequest request){
        Principal principal = request.getUserPrincipal();
        return principal.getName();
    }
}    

通过自定义接口获取用户信息

为了充分利用spring的依赖注入功能,可以在在任何地方获取认证信息,不仅仅是@Controller注解的bean,可以通过简单的门面隐藏静态访问。

import org.springframework.security.core.Authentication;
// 门面接口
public interface IAuthenticationFacade {
    Authentication getAuthentication();
}
//////////////////////////////////
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
// 门面实现类
@Component
public class AuthenticationFacade implements IAuthenticationFacade {
    @Override
    public Authentication getAuthentication() {
        return SecurityContextHolder.getContext().getAuthentication();
    }
}
//////////////////////////////////
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class SecurityController {

    @Autowired
    private IAuthenticationFacade authenticationFacade;

    @GetMapping("/getName")
    @ResponseBody
    public String getName(){
        Authentication authentication = authenticationFacade.getAuthentication();
        return authentication.getName();
    }

在JSP中获取用户信息

当前认证用户也可以在jsp页面中获取到。利用spring security标签支持。需要在页面中定义标签:

<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>

然后可以引用principal:

<security:authorize access="isAuthenticated()">
    authenticated as <security:authentication property="principal.username" /> 
</security:authorize>

在thymeleaf中获取用户信息

可以通过security为thymeleaf增加的扩增标签来实现。
需要导入依赖。

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity4</artifactId>
</dependency>

需要引入sec标签。

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">

通过sec标签获取用户信息。

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

使用总结

  • 引入 Spring Security 相关的依赖。
  • 编写一个配置类,该配置类继承了 WebSecurityConfigurerAdapter ,并在该配置类上加@EnableWebSecurity 注解开启 Web Security。
  • 通过 AuthenticationManagerBuilder 配置读取用户的认证信息的方式,可以从内存中读取,也可以从数据库中读取。
  • 通过 HttpSecurity 配置请求的认证规则,即哪些 URI 请求需要认证、哪些不需要 ,以及需要拥有什么权限才能访问。
  • 通过 @EnableGlobalMethodSecurity(prePostEnabled = true) 注解开启方法级别的安全配置,方法级别上的安全控制支持 secureEnabled、jsr250Enabled、prePostEnabled 3种方式,用的最多的是 prePostEnabled。其中,prePostEnabled 包括 PreAuthorizePostAuthorize两种形式,一般只用到 PreAuthorize 这种方式 。

参考:
SpringBoot2.x整合Security5(完美解决 There is no PasswordEncoder mapped for the id “null”)

Spring Security 无法登陆,报错:There is no PasswordEncoder mapped for the id “null”

SpringBoot2.0整合SpringSecurity并实现验证码和权限控制

springboot 集成 spring security 详细 附代码

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值