加入security+jwt安全策略
Pom中引入
<!-- security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<!-- jwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
加入后访问页面会弹出一个登录页,用户名为user,密码为启动时显示的一串字符串

但是这种页面及默认用户显然不是我们想要的,我们需要用户数据持久化,也需要合理分配权限。如下我们开始对security做基本的设置。
关于security+jwt主要有如下几个类设置
1.新建JwtUserDetails实现UserDetails
package com.tangruo.example.common.security;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
/**
* 安全用户模型
* @author
*/
public class JwtUserDetails implements UserDetails {
private static final long serialVersionUID = 1L;
/**
* 用户名:这是数据库的字段,
* 是userName或者是account就写对应的字段
*/
private String username;
/**
* 密码
*/
private String password;
private String salt;
/**
* 权限集合
*/
private Collection<? extends GrantedAuthority> authorities;
JwtUserDetails(String username, String password, String salt, Collection<? extends GrantedAuthority> authorities) {
this.username = username;
this.password = password;
this.salt = salt;
this.authorities = authorities;
}
/**无论我数据库里的字段是 `account`,或者username,或者userName,或者其他代表账户的字段,
* 这里还是要写成 `getUsername()`,因为是继承的接口
*
* @return
*/
@Override
public String getUsername() {
return username;
}
@JsonIgnore
@Override
public String getPassword() {
return password;
}
public String getSalt() {
return salt;
}
/**
* 返回给用户的角色列表
* @return
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
/**
* 账户是否未过期
* @return
*/
@JsonIgnore
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
*账户是否未锁定
* @return
*/
@JsonIgnore
@Override
public boolean isAccountNonLocked() {
return true;
}
/**
*密码是否未过期
* @return
*/
@JsonIgnore
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
*账户是否激活
* @return
*/
@JsonIgnore
@Override
public boolean isEnabled() {
return true;
}
}
2.新建UserDetailsServiceImpl实现UserDetailsService
package com.rexyn.common.security;
import com.rexyn.system.entity.User;
import com.rexyn.system.service.AuthorityService;
import com.rexyn.system.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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.stereotype.Service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* 用户登录认证信息查询
*
* @author
*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserService sysUserService;
@Autowired
private AuthorityService sysAuthorityService;
private Logger log = LoggerFactory.getLogger(this.getClass());
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
List<String> Permissions;
// 根据用户名查询用户是否存在
User user = sysUserService.findUser(username,null);
if (user == null) {
// 用户不存在
throw new UsernameNotFoundException(String.format("没有该用户 '%s'.", username));
}else {
// 用户存在,继续查询用户所拥有的所有权限
Permissions = sysAuthorityService.findPermissionsByUsername(username);
}
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
if (Permissions != null && Permissions.size() > 0) {
// 遍历权限集合,将权限标识符添加到安全认证中心
for (String nameStr : Permissions) {
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(nameStr);
grantedAuthorities.add(simpleGrantedAuthority);
}
}
return new JwtUserDetails(username, user.getPassword(), user.getSalt(), grantedAuthorities);
}
}
3.权限不足返回,新建AuthenticationAccessDeniedHandler实现AccessDeniedHandler类
package com.tangruo.example.common.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tangruo.example.common.api.ResultJson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.httpclient.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author
*/
@Component
@Slf4j
public class AuthenticationAccessDeniedHandler implements AccessDeniedHandler {
@Autowired
private ObjectMapper objectMapper;
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
// 登陆状态下,权限不足执行该方法
// log.error("权限不足:" + accessDeniedException.getMessage());
response.setStatus(HttpStatus.SC_OK);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter printWriter = response.getWriter();
//printWriter.println(objectMapper.writeValueAsString(Result.fail(HttpStatus.SC_FORBIDDEN, accessDeniedException.getMessage())));
printWriter.println(objectMapper.writeValueAsString(ResultJson.fail(HttpStatus.SC_FORBIDDEN+"", "权限不足,无法访问")));
printWriter.flush();
printWriter.close();
}
}
4.登陆失效设置,新建JwtAuthenticationEntryPoint实现AuthenticationEntryPoint
package com.tangruo.example.common.security;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.httpclient.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tangruo.example.common.api.ResultJson;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {
@Autowired
private ObjectMapper objectMapper;
/**
*
*/
private static final long serialVersionUID = -4957913354424675827L;
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
// 验证为未登陆状态会进入此方法,认证错误
// log.error("认证失败,请求接口:{},请求IP:{},请求参数:{},失败原因:{}", request.getRequestURI(), WebUtil.getIP(request),
// JsonUtil.toJson(request.getParameterMap()), authException.getMessage());
response.setStatus(HttpStatus.SC_OK);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter printWriter = response.getWriter();
//printWriter.write(objectMapper.writeValueAsString(Result.fail(HttpStatus.SC_FORBIDDEN, authException.getMessage())));
printWriter.write(objectMapper.writeValueAsString(ResultJson.fail(HttpStatus.SC_FORBIDDEN+"", "登录已失效,请重新登录")));
printWriter.flush();
printWriter.close();
}
}
5.登陆验证规则重写,新建JwtAuthenticationProvider继承DaoAuthenticationProvider
package com.tangruo.example.common.security;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import com.tangruo.example.common.util.PasswordEncoder;
/**重写身份验证规则
* @author tangruo
*
* 2021年1月4日
*/
public class JwtAuthenticationProvider extends DaoAuthenticationProvider{
public JwtAuthenticationProvider(UserDetailsService userDetailsService) {
setUserDetailsService(userDetailsService);
}
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
if (authentication.getCredentials() == null) {
logger.debug("Authentication failed: no credentials provided");
throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
String presentedPassword = authentication.getCredentials().toString();
String salt = ((JwtUserDetails) userDetails).getSalt();
// 覆写密码验证逻辑
if (!new PasswordEncoder(salt).matches(userDetails.getPassword(), presentedPassword)) {
logger.debug("Authentication failed: password does not match stored value");
throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
}
}
6.新建WebSecurityConfig继承WebSecurityConfigurerAdapter
package com.tangruo.example.common.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
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.core.userdetails.UserDetailsService;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import com.tangruo.example.common.security.AuthenticationAccessDeniedHandler;
import com.tangruo.example.common.security.JwtAuthenticationEntryPoint;
import com.tangruo.example.common.security.JwtAuthenticationProvider;
/**
* 全局@author Sheldon
*/
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* Spring会自动寻找实现接口的类注入,会找到我们的 UserDetailsServiceImpl 类
*/
@Qualifier("userDetailsServiceImpl")
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private AuthenticationAccessDeniedHandler authenticationAccessDeniedHandler;
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
/**
* anyRequest | 匹配所有请求路径
* access | SpringEl表达式结果为true时可以访问
* anonymous | 匿名可以访问
* denyAll | 用户不能访问
* fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录)
* hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问
* hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问
* hasAuthority | 如果有参数,参数表示权限,则其权限可以访问
* hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
* hasRole | 如果有参数,参数表示角色,则其角色可以访问
* permitAll | 用户可以任意访问
* rememberMe | 允许通过remember-me登录的用户访问
* authenticated | 用户登录后可访问
*/
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
// 使用自定义身份验证组件
auth.authenticationProvider(new JwtAuthenticationProvider(userDetailsService));
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// 进行授权成功后处理。授权成功后,重定向回之前访问的页面(获取RequestCache中存储的地址)
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
// 允许页面内嵌显示
http.headers().frameOptions().disable();
// 禁用 csrf, 由于使用的是JWT,我们这里不需要csrf
http.cors().and().csrf().disable()
// 认证失败处理类
.exceptionHandling().accessDeniedHandler(authenticationAccessDeniedHandler)
.and()
.exceptionHandling()
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and()
.authorizeRequests()
// 跨域预检请求
//.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
// 允许对于网站静态资源的无授权访问
.antMatchers(HttpMethod.GET,
"/favicon.ico",
"/**/*.css",
"/**/*.js",
"/**/*.jpg",
"/**/*.png"
).permitAll()
// 静态资源文件夹和swagger
.antMatchers("/lib/**").permitAll()
.antMatchers("/images/**").permitAll()
.antMatchers("/temp/**").permitAll()
.antMatchers("/doc.html").permitAll()
.antMatchers("/swagger-ui.html").permitAll()
.antMatchers("/swagger-resources").permitAll()
.antMatchers("/v2/api-docs").permitAll()
.antMatchers("/webjars/springfox-swagger-ui/**").permitAll()
.antMatchers("/swagger/user/login").permitAll()
// web jars
.antMatchers("/webjars/**").permitAll()
// 查看SQL监控(druid)
.antMatchers("/druid/**").anonymous()
.antMatchers("/home/**").permitAll()
.antMatchers("/finance/**").permitAll()
.antMatchers("/equipment/**").permitAll()
.antMatchers("/equipment/findMainEquipments").permitAll()
// 验证码
.antMatchers("/oauth/captcha**").permitAll()
.antMatchers("/layuiadmin/**").permitAll()
//.antMatchers("").hasAnyAuthority("'',''")
// 注册和登陆
.antMatchers("/pages/system/login.jsp").permitAll()
.antMatchers("/commons/*.jsp").permitAll()
.antMatchers("/").permitAll()
.antMatchers("/user/*").permitAll()
.antMatchers("/index").permitAll()
//所有页面放开权限访问
.antMatchers("/pages/**").permitAll()
//配置生产管理接口访问权限登陆验证
.antMatchers("/production/**").permitAll()
//其他所有请求需要身份认证
.anyRequest().authenticated()
// 无权限的时候调用AuthenticationAccessDeniedHandler
.and().exceptionHandling()
.accessDeniedHandler(getAccessDeniedHandler())
;
// 退出登录处理器
http.logout().logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler());
// token验证过滤器
http.addFilterBefore(new BasicAuthenticationFilter(authenticationManager()),
UsernamePasswordAuthenticationFilter.class);
}
@Bean
@Override
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Bean
public AccessDeniedHandler getAccessDeniedHandler() {
return new AuthenticationAccessDeniedHandler();
}
}
7.新建管理登陆接口类
包含自定义登录接口,登出接口,主页跳转功能
package com.tangruo.example.system.controller;
import com.alibaba.fastjson.JSONObject;
import com.tangruo.example.common.api.ResultJson;
import com.tangruo.example.common.security.CookieUtil;
import com.tangruo.example.common.security.JwtAuthenticatioToken;
import com.tangruo.example.common.security.JwtTokenUtils;
import com.tangruo.example.common.security.SecurityUtils;
import com.tangruo.example.common.util.DateUtils;
import com.tangruo.example.common.util.PasswordUtils;
import com.tangruo.example.common.util.StringUtil;
import com.tangruo.example.system.entity.AuthInfo;
import com.tangruo.example.system.entity.Resource;
import com.tangruo.example.system.entity.User;
import com.tangruo.example.system.service.ResourceService;
import com.tangruo.example.system.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
@Api(value = "用户登陆/退出管理", tags = "用户登陆/退出管理")
@Controller
public class UserLandingController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private UserService sysUserService;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private ResourceService resourceService;
@ApiOperation(value = "跳转主页,做动态菜单处理")
@RequestMapping("/index")
public String index( HttpServletRequest request,HttpServletResponse res) {
Authentication authentication=SecurityContextHolder.getContext().getAuthentication();
String username=authentication.getName();
if (authentication.getName().equals("anonymousUser")||authentication.getPrincipal() instanceof String) {
return "/system/login";
}
List<Resource> resources=resourceService.findByUsername(username);
logger.info(JSONObject.toJSONString(resources));
request.setAttribute("resource", resources);
return "/index";
}
@ApiOperation(value = "主页识别")
@RequestMapping("/")
public void defaultIndex( HttpServletRequest request,HttpServletResponse res) throws IOException{
Authentication authentication=SecurityContextHolder.getContext().getAuthentication();
if (authentication.getName().equals("anonymousUser")||authentication.getPrincipal() instanceof String) {
res.sendRedirect("/pages/system/login.jsp?");
return;
}
res.sendRedirect("/index");
}
@ApiOperation(value = "用户登陆")
@PostMapping("/user/login")
public void sysUserLogin( HttpServletRequest request,HttpServletResponse res) throws IOException{
logger.info("the login is running");
String username=request.getParameter("username");
String password=request.getParameter("password");
if (StringUtil.isBlank(username)||StringUtil.isBlank(password)) {
String msg="请输入用户名或密码";
msg=URLEncoder.encode(msg,"UTF-8");
res.sendRedirect("/pages/system/login.jsp?msg="+msg);
return;
}
User sysUser = sysUserService.findUser(username,null);
ResultJson<Object> resultJson = this.login(username , password,sysUser);
if (resultJson != null) {
String msg=resultJson.getMsg();
msg=URLEncoder.encode(msg,"UTF-8");
res.sendRedirect("/pages/system/login.jsp?msg="+msg);
return;
}
// 系统登录认证
AuthInfo authInfo = this.createAuthInfo(request, username , password);
if (authInfo == null) {
String msg="凭证错误";
msg=URLEncoder.encode(msg,"UTF-8");
res.sendRedirect("/pages/system/login.jsp?msg="+msg);
return;
}
if (!StringUtil.isEmpty(sysUser.getLoginDate())) {
authInfo.setLastUpdateTime(sysUser.getLoginDate());
}
sysUser.setLoginDate(DateUtils.getCurrDate());
sysUserService.saveOrUpdate(sysUser);
sysUser.setPassword(null);
sysUser.setName(sysUser.getName()==null?sysUser.getUsername():sysUser.getName());
HttpSession session = request.getSession();
session.setAttribute("currentUser", sysUser);
res.sendRedirect("/index");
}
// 校验账号和密码
public ResultJson<Object> login(String username, String password,User sysUser) {
String salt;
String objectPassword;
Integer status;
// 用户信息
if (sysUser == null) {
return ResultJson.fail("TX000001" , "账号不存在");
}
salt = sysUser.getSalt();
objectPassword = sysUser.getPassword();
status = sysUser.getEnable();
// 账号不存在、密码错误
if (!PasswordUtils.matches(salt, password, objectPassword)) {
return ResultJson.fail("TX000002" , "密码不正确");
}
// 账号锁定
if (status == 0) {
return ResultJson.fail("TX000003" , "账号已被锁定,请联系管理员");
}
return null;
}
/**
* 生成AuthInfo
*
*/
public AuthInfo createAuthInfo(HttpServletRequest request, String userName, String password) {
try {
JwtAuthenticatioToken token = SecurityUtils.login(request, userName, password, authenticationManager);
logger.info("the token is: " + token);
CookieUtil.writeCookie("token" , token.getToken());
CookieUtil.writeCookie("uid" , userName);
AuthInfo authInfo = new AuthInfo();
authInfo.setTokenType(SecurityUtils.BEARER);
authInfo.setUserName(userName);
authInfo.setToken(token.getToken());
authInfo.setExpiresIn(JwtTokenUtils.getExpire());
return authInfo;
} catch (Exception e) {
logger.error("生成AuthInfo出错" , e);
return null;
}
}
@ApiOperation(value = "登出" , notes = "退出登录")
@GetMapping(value = "/user/logout")
public void logout(HttpServletRequest request,HttpServletResponse response) throws IOException {
String token = StringUtil.isEmpty(request.getHeader("token")) ? CookieUtil.getCookie(request, "token") : request.getHeader("token");
String msg = "退出登录成功";
msg=URLEncoder.encode(msg,"UTF-8");
if (token == null) {
msg="退出登录失败";
response.sendRedirect("/pages/system/login.jsp?msg="+msg);
return;
}
CookieUtil.removeCookie("token");
response.sendRedirect("/pages/system/login.jsp?msg="+msg);
}
}
我用的登陆失效返回都是json数据,如果需要返回登录页,可以对4中进行设置。
有可能在上面的引用中会出现缺少类的问题。我这变引入了很多工具类,项目我重新打了一次压缩包(example-manage-2.0.zip)。可以进项目查看。
下载地址 网盘: https://pan.baidu.com/s/1c44hr0uCfRI_693JII6ylA 提取码: ghbk
返回目录springboot项目创建过程+maven+mybatis-plus+swagger+security
下一章:十.权限的使用
加入security+jwt安全策略的更多相关文章
- Spring Security + JWT实现前后端分离权限认证
现在国内前后端很多公司都在使用前后端分离的开发方式,虽然也有很多人并不赞同前后端分离,比如以下这篇博客就很有意思: https://www.aliyun.com/jiaocheng/650661.ht ...
- Jhipster token签名异常——c.f.o.cac.security.jwt.TokenProvider : Invalid JWT signature.
背景,jHipster自动生成的springBoot和angularJs前后台端分离的项目.java后台为了取到当前登录者的信息,所以后台开放了 MicroserviceSecurityConfigu ...
- Spring Boot整合实战Spring Security JWT权限鉴权系统
目前流行的前后端分离让Java程序员可以更加专注的做好后台业务逻辑的功能实现,提供如返回Json格式的数据接口就可以.像以前做项目的安全认证基于 session 的登录拦截,属于后端全栈式的开发的模式 ...
- 基于Spring Boot+Spring Security+JWT+Vue前后端分离的开源项目
一.前言 最近整合Spring Boot+Spring Security+JWT+Vue 完成了一套前后端分离的基础项目,这里把它开源出来分享给有需要的小伙伴们 功能很简单,单点登录,前后端动态权限配 ...
- Spring Security + JWT学习
开胃:Oauth2认证流程分析 现在第三方登录已经很普遍了,随便哪个App都会有使用微信登录,使用手机号码登录,或者使用支付宝登录等功能... 下面我们就以使用微信登录,做一个简单的流程分析分析 开胃 ...
- Spring Boot Security JWT 整合实现前后端分离认证示例
前面两章节我们介绍了 Spring Boot Security 快速入门 和 Spring Boot JWT 快速入门,本章节使用 JWT 和 Spring Boot Security 构件一个前后端 ...
- Spring Boot+Spring Security+JWT 实现 RESTful Api 认证(二)
Spring Boot+Spring Security+JWT 实现 RESTful Api 认证(二) 摘要 上一篇https://javaymw.com/post/59我们已经实现了基本的登录和t ...
- Spring Boot+Spring Security+JWT 实现 RESTful Api 认证(一)
标题 Spring Boot+Spring Security+JWT 实现 RESTful Api 认证(一) 技术 Spring Boot 2.Spring Security 5.JWT 运行环境 ...
- 4-12 Spring Security + JWT
Spring Security + JWT 此前,在处理登录的业务中,当视为登录成功时,返回的字符串并不是JWT数据,则应该将此数据改为必要的JWT数据. @Service public class ...
- SpringBoot集成Security,JWT,Swagger全分析
GitHub地址: https://github.com/li-jun0201/springsecuritydemo本项目采用SpringBoot1.5.9, SpringSecurity,JWT, ...
随机推荐
- 解决 -Code 安装似乎损坏。请重新安装
问题: 1. 安装插件 fix VSCode Checksums 2. ctrl+shift+P打开命令面板 3. 输入 Fix Checksums: Apply 4. 重新启动VSCode
- 在 openEuler 22.03 上安装 KubeSphere 实战教程
作者:老 Z,中电信数智科技有限公司山东分公司运维架构师,云原生爱好者,目前专注于云原生运维,云原生领域技术栈涉及 Kubernetes.KubeSphere.DevOps.OpenStack.Ans ...
- 云原生周刊:Kubernetes v1.27 发布 | 2023.4.17
开源项目推荐 Palaemon Palaemon 是一个开源开发工具,用于监控 Kubernetes 集群的健康状况和资源指标并分析内存不足 (OOMKill) 错误. Gitkube Gitkube ...
- 干活总结 | SQL 语法速成手册
本文针对关系型数据库的一般语法.限于篇幅,本文侧重说明用法,不会展开讲解特性.原理.本文内容包括基本概念.增删改查.子查询.连接和组合.函数.排序和分组.数据定义.事务处理.权限管理等等. 一.基本概 ...
- Win11安装基于WSL2的Ubuntu
1. 概述 趁着还没有完全忘记,详细记录一下在Win11下安装基于WSL2的Ubuntu的详细过程.不得不说WLS2现在被微软开发的比较强大了,还是很值得安装和使用的,笔者就通过WLS2安装的Ubun ...
- Python3 编程面试题
Python global 语句的作用 lambda 匿名函数好处 Python 错误处理 Python 内置错误类型 简述 any() 和 all() 方法 Python 中什么元素为假? 提高 P ...
- SQL Server创建用户只能访问指定数据库和视图
我们在给数据库用户赋予权限时,有时候不想让该用户看到太多过程表和过程视图,这时就需要限定用户的访问权限 第一步:创建用户 创建数据库连接后,进入安全性--登录名,单击右键,新建登录名,并设置默认数据库 ...
- composer 基础操作
一.composer入门 1.每次安装新的包文件,会更新/vendor/autoload.php文件 2.composer.lock与composer.json的关系 文件composer.lock会 ...
- Paypal绑定招商银行 —— Paypal绑定收款银行账户的注意事项
地址: https://code.newban.cn/446.html
- 5.3 Linux Vim三种工作模式
通过前面的学习我们知道,Linux 系统中所有的内容都以文件的形式进行存储,当在命令行下更改文件内容时,常会用到文本编辑器. 我们首选的文本编辑器是 Vim(至于为什么,可查看<Vi和Vim之间 ...