新建springboot项目
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.20version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.0.5version>
dependency>
<dependency>
<groupId>org.thymeleafgroupId>
<artifactId>thymeleaf-spring5artifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>org.thymeleaf.extrasgroupId>
<artifactId>thymeleaf-extras-java8timeartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-securityartifactId>
dependency>
dependencies>
spring.datasource.url=jdbc:mysql://localhost:3306/textnode?serverTimeZone=UTC&useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
//和数据库字段一样
@Data
@TableName("tian")
public class UserLogin {
@TableId(type = IdType.AUTO)
private int id;
private String name;
private String password;
}
@Mapper
@Repository
public interface UserMapper extends BaseMapper<UserLogin> {
}
public interface UserService extends IService<UserLogin> {
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserLogin> implements UserService {
}
package com.example.springsecuritydemo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Controller
public class LoginController {
// @RequestMapping("/login")
// public String login(){
// return "redirect:main.html";
// }
@RequestMapping("/toMain")
public String toMain(){
return "redirect:main.html";
}
@RequestMapping("/toError")
public String toError(){
return "redirect:error.html";
}
}
package com.example.springsecuritydemo.config;
import com.example.springsecuritydemo.handle.MyAuthenticationFailHandle;
import com.example.springsecuritydemo.handle.MyAuthenticationSuccessHandle;
import com.example.springsecuritydemo.service.UserDetailServiceImpl;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailServiceImpl userDetailService;
/*
// 没有加此段代码 数据库密码如果是明文,UserDetailServiceImpl传入的明文密码登录不进去,加了就可以或者 UserDetailServiceImpl传入的密码是经过加密返回User对象就可以登录成功
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailService).passwordEncoder(getPw()); //注释掉原本从内存中加载用户的代码。 }
}
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
// .usernameParameter("username123")//自定义入参和前端的name属性一样
// .passwordParameter("password123")//自定义入参
.loginPage("/login.html") //自定义登录页面
.loginProcessingUrl("/login")//必须和表单提交的接口一样,回去执行自定义登录逻辑
// .successForwardUrl("/toMain")//登录成功后跳转的页面 POST请求
//前后端分离 跳转不归我们管 编写handle.MyAuthenticationSuccessHandle
.successHandler(new MyAuthenticationSuccessHandle("http://www.baidu.com"))
// .failureForwardUrl("/toError") //登录失败后跳转的页面 POST请求
.failureHandler(new MyAuthenticationFailHandle("/error.html"))//自定义登陆失败处理器
;
//授权
http.authorizeRequests()
//放行 不用登录
.antMatchers("/login.html").permitAll()
//放行 不用登录
.antMatchers("/error.html").permitAll()
//拦截所有请求
.anyRequest().authenticated();
//防止网站攻击
http.csrf().disable();//登录失败可能存在的原因
}
@Bean
public PasswordEncoder getPw() {
return new BCryptPasswordEncoder();
}
}
package com.example.springsecuritydemo.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.springsecuritydemo.entity.UserLogin;
import com.example.springsecuritydemo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.*;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@Service
public class UserDetailServiceImpl implements UserDetailsService{
// @Autowired
// UserService service;
@Autowired
UserMapper mapper;
@Autowired
PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<UserLogin> wrapper = new QueryWrapper<>();
wrapper.eq("name",username);
UserLogin one = mapper.selectOne(wrapper);
if(one==null){
throw new UsernameNotFoundException("用户名不存在");
}
// String password = passwordEncoder.encode(one.getPassword()); //加密后传入
// System.out.println(password);
return new User(username,one.getPassword(), AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal"));
}
}
package com.example.springsecuritydemo.handle;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyAuthenticationFailHandle implements AuthenticationFailureHandler {
private String url;
public MyAuthenticationFailHandle(String url) {
this.url = url;
}
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
response.sendRedirect(url);
}
}
package com.example.springsecuritydemo.handle;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyAuthenticationSuccessHandle implements AuthenticationSuccessHandler {
private String url;
public MyAuthenticationSuccessHandle(String url) {
this.url = url;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.sendRedirect(url);
}
}
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<form action="/login" method="post">
用户名 : <input type="text" name="username">
密码 : <input type="password" name="password">
<input type="submit" value="登录">
form>
body>
html>
error.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
登陆失败
<a href="/login.html">跳到登陆页面a>
body>
html>
main.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
登录成功
</body>
</html>
注意要放在最后面 是按顺序的 ,放最前面其他放行的请求都会被拦截
//授权
http.authorizeRequests()
//放行 不用登录
.antMatchers("/login.html").permitAll()
//放行 不用登录
.antMatchers("/error.html").permitAll()
//拦截所有请求
.anyRequest().authenticated();
放行 静态资源
? 匹配一个字符
* 匹配0个或多个字符
** 匹配0个或多个目录
//例
.antMatchers("/css/**","/js/**","/images/**").permitAll()
.antMatchers("/**/*.png").permitAll()
//正则匹配
.regexMatchers(".+[.]png").permitAll()
//还有一个参数控制请求方法的 必须post才放行
.regexMatchers(HttpMethod.POST,"/demo").permitAll()
//整个项目加前缀访问路径
//只在mvcMatchers里面有servletPath方法
.mvcMatchers("/demo").servletPath("/xxxx").permitAll()
等价于
.antMatchers("/xxxx/demo").permitAll()
控制的permitAll()还有其他的控制方法
//严格区分大小写
.antMatchers("/main1.html").hasAuthority("admin").permitAll()
//只要有一个权限就可以访问
.antMatchers("/main1.html").hasAnyAuthority("admin","admiN").permitAll()
//给用户加角色 必须是 ROLE_ 开头
return new User(username,one.getPassword(), AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal,ROLE_abc"));
//严格区分大小写
.antMatchers("/main1.html").hasRole("abc").permitAll()
//只要有一个角色就可以访问
.antMatchers("/main1.html").hasAnyRole("abc","ABC").permitAll()
.antMatchers("/main1.html").hasIpAddress("127.0.0.1").permitAll()
定义配置类
使用
//写法
.antMatchers("/main1.html").access("permitAll")
.antMatchers("/main1.html").access("hasRole('admin')")
编写接口及其实现类
使用
启动访问main.html 报错 没有 跳转的路径
的权限
添加访问权限
启动访问 成功~
表示用户具有某个角色,可以访问方法
1.启动类开启注解
2.使用
在进入方法之前做验证,看是否有权限进入
区分大小写 可以 加前缀ROLE_
方法执行之后校验 没什么大用
1.导入依赖
基于springjdbc的 但springjdbc很少用 用mybatis+mysql
2.编写mysql连接配置
4.前端加上记住我
1.导入依赖
2.前端页面
3.现象
设置用户角色和权限
直接在前端写上退出链接
<a href="/logout">退出a>
但地址栏会有lougout,不想看见怎么办?
配置类配置
//退出
http.logout()
//自定义退出 前端的退出请求也得是这个 最好就用默认的
//.logoutUrl("/user/logout")
.logoutUrl("/logout")
//退出成功后跳转的页面
.logoutSuccessUrl("/login.html")
跨站请求伪造
跨域: 网络协议 ip地址 端口中任何一个不相同就是跨域请求
此时就登陆不成功
解决
第三方认证技术方案最主要是解决认证协议的通用标准问题,因为要实现跨系统认证,各系统之间要遵循一定的接口协议。
1.新建springboot工程
2.导入依赖 注意springboot版本
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.3.11.RELEASEversion>
<relativePath/>
parent>
<groupId>com.tiangroupId>
<artifactId>springsecurityoauth2artifactId>
<version>0.0.1-SNAPSHOTversion>
<name>springsecurityoauth2name>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
<spring-cloud.version>Greenwich.SR2spring-cloud.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-oauth2artifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-securityartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-surefire-pluginartifactId>
<version>2.22.2version>
<configuration>
<skipTests>trueskipTests>
configuration>
plugin>
plugins>
build>
project>
3.pojo/user
package com.tian.springsecurityoauth2.pojo;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.List;
public class User implements UserDetails {
private String username;
private String password;
private List<GrantedAuthority> authorities;
public User(String username, String password, List<GrantedAuthority> authorities) {
this.username = username;
this.password = password;
this.authorities = authorities;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
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;
}
}
4.service/UserService
package com.tian.springsecurityoauth2.service;
import com.tian.springsecurityoauth2.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
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;
@Service
public class UserService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
String password = passwordEncoder.encode("123456");
return new User(username,password,AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
5.controller/UserController
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/getCurrent")
public Object getCurrent(Authentication authentication){
return authentication.getPrincipal();
}
}
6.config/SecurityConfig
package com.tian.springsecurityoauth2.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth/**","/login/**",
"/logout/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.permitAll()
.and()
.csrf().disable();
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
7.config/AuthorzationServerConfig
package com.tian.springsecurityoauth2.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
@Configuration
@EnableAuthorizationServer
public class AuthorzationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
//客户端ID
.withClient("client")
//密钥
.secret(passwordEncoder.encode("112233"))
//重定向地址
.redirectUris("http://www.baidu.com")
//授权范围
.scopes("all")
//授权类型 - authorization_code 授权码模式
.authorizedGrantTypes("authorization_code");
}
}
8.config/ResourceServerConfig
package com.tian.springsecurityoauth2.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated()
.and().requestMatchers()
.antMatchers("/user/**")
;
}
}
启动访问
http://localhost:8080/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://www.baidu.com&scope=all
返回到springsecurity自定义的登录页面
输入 admin 123456 跳到这个页面 点击允许 跳转到百度
注意百度地址栏有个授权码
拿着返回的token请求资源
实际上token不会存在内存,我们这边用redis存储
1.添加依赖
2.配置文件
3.配置类
4.使用
是一个标准
是JWT的实现
1.创建springboot项目
2.导入依赖
3.启动类
4.测试
5.现象
现象
获取