Myconfig.java
package com.neuedu.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import javax.annotation.Resource;
@Configuration
public class MyConfig {
@Bean
BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
CorsFilter corsFilter(){
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration configuration = new CorsConfiguration();
configuration.addAllowedOrigin("*");
configuration.addAllowedMethod("*");
configuration.addAllowedHeader("*");
source.registerCorsConfiguration("/**",configuration);
return new CorsFilter(source);
}
@Resource
RedisTemplate redisTemplate;
@Bean
RedisTemplate<String,String> getRedisTemplate(){
RedisSerializer<String> stringRedisSerializer = new StringRedisSerializer();
redisTemplate.setValueSerializer(stringRedisSerializer);
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setHashValueSerializer(stringRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
return redisTemplate;
}
}
JwtAuthentication.java
package com.neuedu.security;
import com.neuedu.pojo.UmsUser;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
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;
import java.util.ArrayList;
import java.util.Enumeration;
//和过滤器很像啊
//这个写好后方进入ioc容器
@Component
public class JWTAuthentication extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
String jwt = httpServletRequest.getHeader("token");
// Enumeration<String> headerNames = httpServletRequest.getHeaderNames();
// if(headerNames.hasMoreElements()){
// System.out.println(headerNames.nextElement());//host
// }
//System.out.println(httpServletRequest.getMethod()); //OPTIONS
if(!"OPTIONS".equals(httpServletRequest.getMethod())){
System.out.println(jwt);
//解析出jwt ,拿到username
//通过username 到 redis 中 查看 key是否存在
//如果存在, 则从redis 中取出 user 对象, 和jwt 中进行密码校验
//如果都对,则可以通过认证
}
//
// //生产一个umsUser对象
// UmsUser umsUser = new UmsUser();
// umsUser.setUsername("admin");
// umsUser.setPassword("1234");
// UserDetails userDetails = new UmsUserDetails(umsUser);
//
//
// UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
// //有这句就表示有身份认证*********
// SecurityContextHolder.getContext().setAuthentication(token);
filterChain.doFilter(httpServletRequest,httpServletResponse);
}
}
RestNoToken.java 自定义错误
package com.neuedu.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.neuedu.util.CommonResult;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class RestNoToken implements AuthenticationEntryPoint {
@Resource
ObjectMapper objectMapper;
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setHeader("Access-Control-Allow-Origin","*");
httpServletResponse.setCharacterEncoding("utf-8");
httpServletResponse.setContentType("text/html;charset=utf-8");
httpServletResponse.getWriter().write(objectMapper.writeValueAsString( CommonResult.notoken()));
}
}
SecurityConfig.java
package com.neuedu.security;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.annotation.Resource;
@Configuration
//如何配置spring-security呢?首先建立一个类,放进ioc容器,
// 并且必须继承WebSecurityConfigurerAdapter
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
RestNoToken restNoToken;
@Resource
JWTAuthentication jwtAuthentication;
//必须重写configurer方法
@Override
protected void configure(HttpSecurity http) throws Exception {
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry
registry = http.authorizeRequests();
//所有的option都通过
registry.antMatchers(HttpMethod.OPTIONS)
.permitAll();
//这句话的意思是除了/index不需要身份验证,其余都需要身份验证,其中antMatchers里面
//的参数可以写多个,配置不用认证的地址
registry.antMatchers(HttpMethod.POST,"/ums-user/login")
.permitAll()
.antMatchers("/index")
.permitAll()
.anyRequest()
.authenticated();
//前后分离的话就是把下面的配置一下,关闭session
registry.and()
.csrf()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//自定义没有认证返回什么东西,如果自定义没有权限的返回内容,就必须自己写个类
//自定义没有认证返回的内容
registry.and()
.exceptionHandling()
.authenticationEntryPoint(restNoToken);
//下一步是怎么才能让他有认证
//如果自定义认证方式,必须自己写一个类,
// 实际上是一个过滤器,必须继承一个父类
//自定义验证
registry.and()
.addFilterBefore(jwtAuthentication, UsernamePasswordAuthenticationFilter.class);
}
}
UmsUserDetails.java
package com.neuedu.security;
import com.neuedu.pojo.UmsUser;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UmsUserDetails implements UserDetails {
private UmsUser umsUser;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
//用户信息
@Override
public String getPassword() {
return umsUser.getPassword();
}
@Override
public String getUsername() {
return umsUser.getUsername();
}
//这几个是 是否已经失效了
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return false;
}
}
IRedisService.java
package com.neuedu.service;
public interface IRedisService {
void set(String key,String value, long time);
String get(String key);
boolean haskey(String key);
boolean expire(String key ,long time);
}
RedisServiceImpl.java
package com.neuedu.service.impl;
import com.neuedu.service.IRedisService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
@Service
public class RedisServiceImpl implements IRedisService {
@Resource
RedisTemplate<String,String> redisTemplate;
@Override
public void set(String key, String value, long time) {
redisTemplate.opsForValue().set(key,value,time, TimeUnit.SECONDS);
}
@Override
public String get(String key) {
return redisTemplate.opsForValue().get(key);
}
@Override
public boolean haskey(String key) {
return redisTemplate.hasKey(key);
}
@Override
public boolean expire(String key, long time) {
return redisTemplate.expire(key,time,TimeUnit.SECONDS);
}
}
JWTUtil.java---json web token(令牌)
package com.neuedu.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.neuedu.pojo.UmsUser;
import java.time.ZoneOffset;
public class JWTUtil {
public static final String KEY = "umsuser";
public static String create(UmsUser user){
String jwt = JWT.create()
.withClaim("username",user.getUsername())
.withClaim("password",user.getPassword())
.withClaim("timestamp",user.getLastlogin().toInstant(ZoneOffset.of("+8")).toEpochMilli())
.sign(Algorithm.HMAC256(KEY));
return jwt;
}
}
ResoultCode.java(封装结果的枚举类)
package com.neuedu.util;
import lombok.Getter;
@Getter
public enum ResultCode {
SUCCESS(200,"操作成功"),
FAILED(500,"操作失败"),
NOTOKEN(401,"未登录或者登陆已经超时"),
NOPREMISS(403,"没有权限")
;
private Integer code;
private String message;
ResultCode(Integer code, String message) {
this.code = code;
this.message = message;
}
}
通用的封装结果 CommonResult.java
package com.neuedu.util;
import lombok.Getter;
@Getter
public class CommonResult {
private Integer code;
private String message;
private Object obj;
private CommonResult(Integer code, String message, Object obj) {
this.code = code;
this.message = message;
this.obj = obj;
}
public static CommonResult success(Object obj)
{
return new CommonResult(ResultCode.SUCCESS.getCode(),ResultCode.SUCCESS.getMessage(),obj);
}
public static CommonResult failed()
{
return new CommonResult(ResultCode.FAILED.getCode(),ResultCode.FAILED.getMessage(),null);
}
public static CommonResult failed(String msg)
{
return new CommonResult(ResultCode.FAILED.getCode(),msg,null);
}
public static CommonResult notoken()
{
return new CommonResult(ResultCode.NOTOKEN.getCode(),ResultCode.NOTOKEN.getMessage(),null);
}
public static CommonResult nopremiss()
{
return new CommonResult(ResultCode.NOPREMISS.getCode(),ResultCode.NOPREMISS.getMessage(),null);
}
}
Mytest.java---测试类
package test;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.neuedu.App;
import com.neuedu.pojo.UmsUser;
import com.neuedu.service.IUmsUserService;
import org.jasypt.encryption.StringEncryptor;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
public class Mytest {
@Resource
RedisTemplate redisTemplate;
@Resource
IUmsUserService iUmsUserService;
@Resource
StringEncryptor stringEncryptor;
@Resource
BCryptPasswordEncoder encoder;
@Test
public void handler(){
UmsUser user = new UmsUser(
"abc",
"1234",
LocalDateTime.now(),
1
);
System.out.println(iUmsUserService.saveOrUpdate(user));
}
@Test
public void handlerjasypt(){
//System.out.println(stringEncryptor.encrypt("1234"));//XGHSdlg7WW4jMVKIBQ8u5Q==
System.out.println(stringEncryptor.encrypt("root"));//HspPg+u2KikM9Yb2sUuB5A==
// System.out.println(stringEncryptor.decrypt("XGHSdlg7WW4jMVKIBQ8u5Q=="));
}
@Test
public void handlerList(){
System.out.println(iUmsUserService.list());
}
@Test
public void test(){
System.out.println(encoder.encode("1234"));
//$2a$10$uCGgugvM8BQsyVuhEFmrKONlZEimz3VfYEgsz0funoLYuugSykRVq
}
@Test
public void testredis(){
//注入一个redistTemplate,然后配置一下要连接的服务器是哪个
redisTemplate.opsForValue().set("a","abc",60, TimeUnit.SECONDS);
System.out.println("保存完成");
}
public static void main(String[] args) {
// String jwt = JWT.create()
// .withClaim("username","admin")
// .withClaim("password","1234")
// .withClaim("a","abcd")
// .sign(Algorithm.HMAC256("user"));
//
// System.out.println(jwt);
//eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhIjoiYWJjZCIsInBhc3N3b3JkIjoiMTIzNCIsInVzZXJuYW1lIjoiYWRtaW4ifQ.HGbHvWY9lcDVj1bVYSlsDM1APMGhqxOy11RtyrqKRKk
//有他就被看做已经被认证过的东西了
String jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6IiQyYSQxMCRjNUhyVDhFU3g5S3dUMUpibi5VRGIueXZoZFRpWHdncng3MzhhZXhlcEZkaUhPYktGT25odSIsInVzZXJuYW1lIjoiYWRtaW4iLCJ0aW1lc3RhbXAiOjE1OTc2NzU1ODg4NDJ9.lY-gdfSl-lLHCQ_VFm1hYiN9bD_HwpneyyJ1xcf23jE";
DecodedJWT decode = JWT.decode(jwt);
//拿到username后 是否 可以 根据username 到 redis中取出 value
//redis中的key 是 umsuser-username,如果拿不到说明未登录或者超时,
//如果能够拿到,就可以将redis中的value 反序列化 为 UmsUser对象
// 反序列化结束后还要 对比 token 中 password和 time是否 UmsUser对象一致
String username = decode.getClaim("username").asString();//damin
String password = decode.getClaim("password").asString();//1234
Long timestamp = decode.getClaim("timestamp").asLong();
System.out.println(username+"---->"+password+"---->"+timestamp);
}
}
UmsUserController.java
package com.neuedu.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.neuedu.pojo.UmsUser;
import com.neuedu.service.IUmsUserService;
import com.neuedu.util.CommonResult;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* <p>
* 前端控制器
* </p>
*
* @author liuyong
* @since 2020-08-14
*/
@RestController
@RequestMapping("/ums-user")
public class UmsUserController {
@Resource
IUmsUserService iUmsUserService;
@PostMapping("/login")
CommonResult login(UmsUser umsUser) throws JsonProcessingException {
String jwt = iUmsUserService.token(umsUser);
if(jwt != null){
return CommonResult.success(jwt);
}
else{
return CommonResult.failed("用户名或密码错误");
}
}
}
本博客仅作为笔记方便记忆---请勿用作其他用途