第一步以来引入:
重要部分有两处
<?xml version="1.0" encoding="UTF-8"?>
<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.xm.demo</groupId>
<artifactId>security</artifactId>
<version>1.0-SNAPSHOT</version>
<name>security</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<thymeleaf.version>3.0.8.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
<thymeleaf-extras-springsecurity4.version>3.0.2.RELEASE</thymeleaf-extras-springsecurity4.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.36</version>
</dependency>
<!--连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.14</version>
</dependency>
<!--mybatisplus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatisplus-spring-boot-starter</artifactId>
<version>1.0.5</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>2.1.8</version>
</dependency>
<!--连接数据库加密-->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>1.16</version>
</dependency>
<!--redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--视图解析器依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
<!-- security安全控件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--页面解析-->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.2.RELEASE</version>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
第二步数据库相关依赖
第三步实体类
package com.security.entity;
import com.baomidou.mybatisplus.annotations.TableField;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
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.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* 用户信息
*
* @author
* @date 2018/07/16
*/
@TableName("user_info")
public class UserInfo {
@TableId(value="id", type= IdType.AUTO)
private Long id;
//名称
private String username;
//密码
private String password;
//用户角色
@TableField(exist = false)
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 List<SysRole> getRoles() {
return roles;
}
public void setRoles(List<SysRole> roles) {
this.roles = roles;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
角色
package com.security.entity;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import org.springframework.security.core.GrantedAuthority;
/**
* 角色
*/
@TableName("sys_role")
public class SysRole {
//主键
@TableId(value="id", type= IdType.AUTO)
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;
}
}
用户角色
package com.security.entity;
import com.baomidou.mybatisplus.annotations.TableField;
import com.baomidou.mybatisplus.annotations.TableName;
/**
*
*/
@TableName("sys_user_role")
public class SysUserRole {
//用户ID
@TableField("user_id")
private Long userId;
//权限ID
@TableField("role_id")
private Long roleId;
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Long getRoleId() {
return roleId;
}
public void setRoleId(Long roleId) {
this.roleId = roleId;
}
}
第四步权限配置
package com.security.config;
import com.security.security.CustomUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
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.builders.WebSecurity;
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;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @Classname WebSecurityConfig
* @Date 2019/6/6 16:20
* @Created xm
* @Description 权限配置
*/
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 启用方法安全设置
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//用户验证服务
@Autowired
private CustomUserService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(charSequence.toString());
}
});
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//指定无需拦截地址,一般为静态资源
.antMatchers("/static","/register")
.permitAll()
.anyRequest().authenticated()
.and()
// 设置登陆页
.formLogin().loginPage("/login")
// 设置登陆成功页
.defaultSuccessUrl("/index").permitAll()
.and()
.logout().permitAll()
.and()
//开启cookie保存用户数据
.rememberMe()
//设置cookie有效期
.tokenValiditySeconds(3600);
// 关闭CSRF跨域
http.csrf().disable();
}
@Override
public void configure(WebSecurity web) throws Exception {
// 设置拦截忽略文件夹,可以对静态资源放行
web.ignoring().antMatchers("/css/**", "/js/**");
}
}
package com.security.security;
import com.security.entity.SysRole;
import com.security.entity.UserInfo;
import com.security.mapper.UserInfoMapper;
import com.security.service.SysRoleService;
import com.security.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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;
import java.util.ArrayList;
import java.util.List;
/**
* @Classname CustomUserService
* @Date 2019/6/6 16:28
* @Created xm
* @Description 自定义验证实体
*/
@Service
public class CustomUserService implements UserDetailsService{
//用户服务对象
@Autowired
private UserInfoService userInfoService;
//权限服务对象
@Autowired
private SysRoleService sysRoleService;
//用户名登录验证
@Override
public UserDetails loadUserByUsername(String username) { //重写loadUserByUsername 方法获得 userdetails 类型用户
UserInfo user = userInfoService.findByName(username);
if(user == null){
System.out.println("用户不存在!");
throw new UsernameNotFoundException("用户名不存在");
}
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
//根据用户ID查询权限
List<SysRole> sysRoles = sysRoleService.findById(user.getId());
for (SysRole sysRole : sysRoles) {
authorities.add(new SimpleGrantedAuthority(sysRole.getName()));
}
return new org.springframework.security.core.userdetails.User(user.getUsername(),
user.getPassword(), authorities);
}
}
第五步,前端控制器
package com.security.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Classname UserController
* @Date 2019/6/6 15:19
* @Created xm
* @Description TODO
*/
@Controller
@RequestMapping
public class UserController {
@GetMapping("/index")
public String index(){
String name = SecurityContextHolder.getContext().getAuthentication().getName();
System.out.println("当前登录用户名:" + name);
return "index";
}
@GetMapping("/admin")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String admin(){
return "admin";
}
@GetMapping("/user1")
@PreAuthorize("hasRole('ROLE_USER')")
public String user1(){
return "user1";
}
@GetMapping("/user2")
@PreAuthorize("hasRole('ROLE_USER2')")
public String user2(){
return "user2";
}
@GetMapping("/login")
public String login(){
return "login";
}
@GetMapping("/403")
public String error(){
return "403";
}
}
第六步前端页面
登录页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陆</title>
</head>
<body>
<h1>登陆</h1>
<form method="post" action="/login">
<div>
用户名:<input type="text" name="username">
</div>
<div>
密码:<input type="password" name="password">
</div>
<div>
<button type="submit">立即登陆</button>
</div>
</form>
</body>
</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>
<meta charset="UTF-8">
<title>主页</title>
</head>
<body sec:authorize="isAuthenticated()">
<button onclick="window.location.href='/logout'">退出登录</button>
<button sec:authorize="hasRole('ROLE_ADMIN')" onclick="window.location.href='/admin'">超级用户</button>
<button sec:authorize="hasRole('ROLE_USER')" onclick="window.location.href='/user1'">普通用户1</button>
<button sec:authorize="hasRole('ROLE_USER2')" onclick="window.location.href='/user2'">普通用户2</button>
</body>
</html>
登录效果