标签:String spring springframework 学习 org import security public
Spring -Security学习
本质上是一个过滤链
SpringSecurity主要包括认证和授权两大功能。
认证:确实是否登录
授权:限制访问权限
认证授权注解使用
1、@Secured
使用方法:在启动类添加 开启此注解使用
添加注解
@EnableGlobalMethodSecurity(securedEnabled = true)
2、在controller方法的注解上添加注解。
示例:
@RequestMapping("/level3/{id}")
@Secured({"ROLE_ADMIN","ROLE_MANAGER"})
public String level3(@PathVariable("id") int id){
return "views/level3/"+id;
}
2、@PreAuthorize
使用方法:在启动类上添加以下注解:
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
PreAuthorize该注解源码注释,值是一个el表达式,在调用之前被调用
public @interface PreAuthorize {
/**
* @return the Spring-EL expression to be evaluated before invoking the protected
* method
*/
String value();
}
controller中
3、@PostAuthorize
在方法执行之后进行验证,可以进行一些处理
使用方法:在启动类上添加以下注解:
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rxLKj0bQ-1627905031861)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210802152437702.png)]
4、@PostFilter
权限验证之后对数据进行过滤
自动登录技术
使用token
实现
1、创建数据表(或者在代码中自动创建)
create table learn.persistent_logins
(
username varchar(64) not null,
series varchar(64) not null
primary key,
token varchar(64) not null,
last_used timestamp default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP
);
2、修改配置类
注入数据源,配置操作数据对象
@Autowired
DataSource dataSource;
//配置对象
@Bean
public PersistentTokenRepository persistentTokenRepository(){
JdbcTokenRepositoryImpl jdbcTokenRepository= new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
//jdbcTokenRepository.setCreateTableOnStartup(true); //启动的时候创建一个数据表
return jdbcTokenRepository;
}
3、配置类中配置自动登录
@Override
protected void configure(HttpSecurity http) throws Exception {
// 定制请求的授权规则
// 首页所有人可以访问
http.and()
.rememberMe() //记住我
.tokenRepository(persistentTokenRepository()) //配置token仓库
.userDetailsService(userDetailsService) //配置查询的用户数据服务
.tokenValiditySeconds(60) //配置有效时间,单位秒
;
}
4、页面添加记住我复选框
<div><input type="checkbox" name="remember-me" title="记住密码"></div>
name属性必须是remember-me
完整项目
1、导入pom依赖
<!-- JDBC-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- spring security -->
<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.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>3.8.0</version>
</dependency>
<!-- 代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!-- 模板依赖-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-log4j -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
<version>1.3.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
<!-- thymeleaf-extras-shiro -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.crazycake/shiro-redis -->
<!-- Shiro redis 缓存-->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>3.3.1</version>
</dependency>
application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost/learn?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
thymeleaf:
cache: false
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
server:
port: 8001
sql建表
create table learn.user #用户表
(
id int auto_increment
primary key,
name varchar(20) null,
password varchar(20) null,
age int null,
gender int default 0 null,
role varchar(20) null
);
create table learn.persistent_logins #用来存储记住我的选项
(
username varchar(64) not null,
series varchar(64) not null
primary key,
token varchar(64) not null,
last_used timestamp default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP
);
配置类:
MybatisPlusConfig
package com.security.Config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.security.mapper")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
//分页插件
@Bean
public PaginationInnerInterceptor paginationInnerInterceptor(){return new PaginationInnerInterceptor();}
}
P6SpyLogger用于打印sql查询语句分析
import com.p6spy.engine.spy.appender.MessageFormattingStrategy;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
public class P6SpyLogger implements MessageFormattingStrategy {
private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
@Override
public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql, String s4) {
return !"".equals(sql.trim()) ? this.format.format(new Date()) + " | took " + elapsed + "ms | " + category + " | connection " + connectionId + "\n " + sql + ";" : "";
}
}
WebMvcConfig
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/index").setViewName("index");
registry.addViewController("/error").setViewName("error");
registry.addViewController("/403").setViewName("403");
}
}
SecurityConfig
import com.security.service.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import javax.sql.DataSource;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsServiceImpl userDetailsService;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// 定制请求的授权规则
// 首页所有人可以访问
http
.authorizeRequests().antMatchers("/","/login").permitAll()
// .antMatchers("/level1/**").hasRole("ADMIN") //role和authority有什么区别
//.antMatchers("/level2/**").hasAnyRole("vip1","vip2")
//.antMatchers("/level3/**").hasAuthority("vip3")
//.antMatchers("/level3/**").hasAnyAuthority("vip1","vip2")//有任何其中某一个权限就可以访问
.and()
.exceptionHandling().accessDeniedPage("/403") //配置403界面
.and()
.logout() //配置推出注销
.logoutUrl("/logout") //注销的url链接
.logoutSuccessUrl("/index") //注销成功的页面跳转
.permitAll()
.and()
.rememberMe() //记住我
.tokenRepository(persistentTokenRepository()) //配置token仓库
.userDetailsService(userDetailsService) //配置查询的用户数据服务
.tokenValiditySeconds(60) //配置有效时间,单位秒
;
//定制请求的授权规则
//....
//开启自动配置的注销的功能
// /logout 注销请求
http
.formLogin()
.loginPage("/dologin") //登录链接
.successForwardUrl("/success") //成功的页面转发
.failureForwardUrl("/error"); //错误的页面转发
}
// 定义认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在内存中定义,也可以在jdbc中去拿....
//在这里在数据库中查询
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Autowired
DataSource dataSource;
//配置对象
@Bean
public PersistentTokenRepository persistentTokenRepository(){
JdbcTokenRepositoryImpl jdbcTokenRepository= new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
//jdbcTokenRepository.setCreateTableOnStartup(true); //启动的时候创建一个数据表
return jdbcTokenRepository;
}
}
//pojo实体类
@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="User对象", description="")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Integer id;
private String name;
private String password;
private String role;
}
//UserMapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface UserMapper extends BaseMapper<User> {
}
//================
<?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.security.mapper.UserMapper">
</mapper>
MyUserDetailService
import com.security.mapper.UserMapper;
import com.security.pojo.User;
import com.security.service.impl.USERervice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.GrantedAuthority;
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.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collection;
@Service
//重写UserDetailsService的loadUserByUsername方法
public class MyUserDetailService implements UserDetailsService {
@Autowired(required = false)
private USERervice useRervice;
@Autowired
PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
User user =useRervice.queryByName(name);
if (user==null){
return null;
}else {
//创建一个权限的集合
Collection<GrantedAuthority> authorities = new ArrayList<>();
//添加获取权限
authorities.add(new SimpleGrantedAuthority(user.getRole()));
//把对象信息(用户名,密码,权限)存入对象,返回该对象,controller层直接调用
org.springframework.security.core.userdetails.User user2 =new org.springframework.security.core.userdetails.User(user.getName(), passwordEncoder.encode(user.getPassword()), authorities);
System.out.println("管理员信息:"+user.getName()+" "+passwordEncoder.encode(user.getPassword())+" "+user2.getAuthorities());
return user2;
}
}
}
controller
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class BaseController {
@RequestMapping({"/","/index","index.html"})
public String index(){
return "index";
}
@RequestMapping("/login.html")
public String LoginHtml(){
return "login";
}
@RequestMapping("/loginout")
public String loginout(){
return "login";
}
@RequestMapping("/level1/{id}")
@PostAuthorize("hasAuthority('MANAGER')")
public String level1(@PathVariable("id") int id){
System.out.println("已处理》》》》》》》》》》》》》》》》"); //此处执行
return "views/level1/"+id; //不返回,无权限
}
@RequestMapping("/level2/{id}")
@Secured({"ROLE_VIP2","ROLE_EMPLOYEE"})
public String level2(@PathVariable("id") int id){
return "views/level2/"+id;
}
@RequestMapping("/level3/{id}")
@PreAuthorize("hasRole('ROLE_VIP3')")
public String level3(@PathVariable("id") int id){
return "views/level3/"+id;
}
@PostMapping("/success")
public String toLogin(){
return "redirect:index";
}
}
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-springsecurity5">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body align="center">
<div> <a th:href="@{/login.html}">登陆界面</a></div>
<div > <a th:href="@{/loginout}">注销</a></div>
<hr/>
<div >
<div><a th:href="@{/level1/1}">level1-view1</a> </div>
<div><a th:href="@{/level1/2}">level1-view2</a> </div>
<div><a th:href="@{/level1/3}">level1-view3</a> </div>
</div>
<div>
<div><a th:href="@{/level2/1}">level2-view1</a> </div>
<div><a th:href="@{/level2/2}">level2-view2</a> </div>
<div><a th:href="@{/level2/3}">level2-view3</a> </div>
</div>
<div>
<div><a th:href="@{/level3/1}">level3-view1</a> </div>
<div><a th:href="@{/level3/2}">level3-view2</a> </div>
<div><a th:href="@{/level3/3}">level3-view3</a> </div>
</div>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body align="center">
<form th:action="@{/dologin}" method="post">
<div><input placeholder="用户名" type="text" name="username"></div>
<div><input placeholder="密码" type="text" name="password"></div>
<div><input type="checkbox" name="remember-me" title="记住密码"></div>
<div><input type="submit" ></div>
</form>
</body>
</html>
error.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body align="center">
<h1>错误</h1>
</body>
</html>
我的疑惑:hasRole与hasAuthority有什么区别?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vt5aG6ce-1627905031858)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210802144202247.png)]
hasRole
hasAnyRole
hasAuthority
hasAnyAuthority
点开源码:
hasRole
private static String hasRole(String role) {
Assert.notNull(role, "role cannot be null");
Assert.isTrue(!role.startsWith("ROLE_"),
() -> "role should not start with 'ROLE_' since it is automatically inserted. Got '" + role + "'");
return "hasRole('ROLE_" + role + "')";
}
hasAuthority
private static String hasAuthority(String authority) {
return "hasAuthority('" + authority + "')";
}
就是说:role会自动加前缀 ROLE_ ,所以在数据库中,role字段的前面也必须加ROLE_
标签:String,spring,springframework,学习,org,import,security,public 来源: https://blog.csdn.net/qq_43876243/article/details/119332666
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。