Security+Jwt登录
Security工作原理


1.依赖
点击查看代码
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</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>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--knife4j-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.9</version>
</dependency>
</dependencies>
2.配置
点击查看代码
spring.datasource.url=jdbc:mysql://localhost:3306/mall_ams?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=admin
mybatis.mapper-locations=classpath:mapper/*.xml
#开启日志权限
logging.level.com.example.springsecurity.demo=trace
knife4j.enable=true
3.自定义UserDetails
点击查看代码
package com.example.springsecurity.demo.config;
import com.example.springsecurity.demo.entity.User;
import com.example.springsecurity.demo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
/**
* @Author QingHao
* @Date: 2022/06/05/ 16:24
* @Describe
*/
@Configuration
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserMapper mapper;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
//调用mapper接口查询数据
User usernamePassword = mapper.getByUsername(s);
//根据mapper查询的数据判断当前用户是否存在
if (usernamePassword == null) {
throw new RuntimeException("用户名或密码错误");
}
//将要返回的UserDetails对象设置好并返回
return org.springframework.security.core.userdetails.User.builder()
.username(s)
.password(usernamePassword.getPassword())
.accountExpired(false)
.accountLocked(false)
.credentialsExpired(false)
.authorities("权限待定")
.build();
}
}
4.自定义WebSecurityConfigurerAdapter
点击查看代码
package com.example.springsecurity.demo.config;
import com.example.springsecurity.demo.filter.JwtAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
* @Author QingHao
* @Date: 2022/06/05/ 16:32
* @Describe
*/
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Bean
public PasswordEncoder PasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//关闭csrf防止攻击
http.csrf().disable()
//关闭session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
String[] urls = {
"/favicon.ico",
"/doc.html",
"/**/*.js",
"/**/*.css",
"/swagger-resources",
"/v2/api-docs",
"/user/login"
};
http.authorizeRequests().antMatchers(urls).permitAll()
.anyRequest().authenticated();
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
5.login
点击查看代码
package com.example.springsecurity.demo.service.impl;
import com.alibaba.fastjson.JSON;
import com.example.springsecurity.demo.entity.User;
import com.example.springsecurity.demo.mapper.UserMapper;
import com.example.springsecurity.demo.service.IUserLoginService;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.stereotype.Service;
import java.util.HashMap;
/**
* @Author QingHao
* @Date: 2022/06/05/ 16:46
* @Describe
*/
@Slf4j
@Service
public class UserServiceImpl implements IUserLoginService {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserMapper mapper;
@Override
public String logIn(String username, String password) {
log.debug("接收到前端数据,suername:>{},password:>{}", username, password);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
authenticationManager.authenticate(authenticationToken);
JwtBuilder builder = Jwts.builder();
User admin = mapper.getByUsername(username);
HashMap<String, Object> map = new HashMap<>();
map.put("user", JSON.toJSONString(admin));
String compact = builder.setHeaderParam(Header.TYPE, Header.JWT_TYPE)
.setHeaderParam(Header.CONTENT_TYPE, "HS256")
.setClaims(map)
//有效期12小时
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12))
.signWith(SignatureAlgorithm.HS256, "asdqweasdaseqweqw")
.compact();
return compact;
}
}
6.过滤器OncePerRequestFilter
点击查看代码
package com.example.springsecurity.demo.filter;
import com.alibaba.fastjson.JSON;
import com.example.springsecurity.demo.entity.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Author QingHao
* @Date: 2022/06/05/ 17:04
* @Describe
*/
@Slf4j
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
//获取请求头
String tonck = httpServletRequest.getHeader("Authentication");
log.debug("请求头>>{}", tonck);
//判断当前请求头是否存在数据
if (!StringUtils.hasText(tonck)) {
filterChain.doFilter(httpServletRequest, httpServletResponse);
return;
}
JwtParser parser = Jwts.parser();
Claims claims = null;
User admin = null;
try {
//解析jwt
claims = parser.setSigningKey("asdqweasdaseqweqw").parseClaimsJws(tonck).getBody();
//获取当前user对应的数据
Object user = claims.get("user");
log.debug("获取到Object类型数据>>{}", user);
//获取到存入的JSON数据后解析为对象
admin = JSON.parseObject(user.toString(), User.class);
log.debug("解析完成的数据>>>{}", admin);
} catch (Exception e) {
e.printStackTrace();
httpServletResponse.setContentType("application/json; charset=utf-8");
httpServletResponse.getWriter().println("非法的请求头");
return;
}
//因为SecurityContextHolder中存入的数据类型为Authentication所以借用实现类存入数据UsernamePasswordAuthenticationToken三参的数据内部带有登录成功的标识
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(admin.getUsername(), null, null);
//将数据设置给SecurityContextHolder
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
//放行继续执行过滤链
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}

浙公网安备 33010602011771号