SpringBoot 之集成Security

快速入门

导入依赖

<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 详细 附代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值