mysql 用户同时登陆_springboot+security+jwt+mysql 动态权限 利用拦截器+token实现一个账号不能多人同时登陆...

一、数据库

fa402de375891d12b891b1866ec0411d.png

二、controller

package cn.**.controller;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.security.core.context.SecurityContextHolder;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

/**

* @ProjectName: springbootSecurity

* @Package: cn.cn.***.security.controller

* @Author: huat

* @Date: 2019/12/12 14:56

* @Version: 1.0

*/

@RestController

public class UserController {

@RequestMapping("/index")

public String login(){

return "index";

}

@RequestMapping("test")

public String test(){

return "hello test";

}

}

三、service

package cn.**.service;

import cn.**.dao.UserDao;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.security.core.userdetails.UserDetails;

import org.springframework.security.core.userdetails.UsernameNotFoundException;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import org.springframework.stereotype.Service;

/**

* @ProjectName: springbootSecurity

* @Package: cn.cn.**.utile

* @Author: huat

* @Date: 2019/12/12 14:48

* @Version: 1.0

*/

@Service//将这个类注入到spring容器中

public class UserServiceImpl implements UserService {

@Autowired

private UserDao userDao;

@Override

public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

return userDao.getUser(s);

}

四、dao

package cn.**.dao;

import cn.**.entity.AuthorityUser;

import org.apache.ibatis.annotations.Mapper;

import org.apache.ibatis.annotations.Param;

/**

* @ProjectName: springbootSecurity

* @Package: cn.cn.**.security.dao

* @Author: huat

* @Date: 2019/12/12 15:04

* @Version: 1.0

*/

@Mapper

public interface UserDao {

/**

* 根据用户名查询角色

* @param username 用户名

* @return

*/

AuthorityUser getUser(@Param("username") String username);

/**

* 添加用户

* @param username 用户名

* @param password 密码

* @return

*/

int saveUser(@Param("username") String username, @Param("password") String password);

/**

* 保存token

* @param id

* @param token

* @return

*/

int updateUserToken(@Param("id")int id,@Param("token")String token);

/**

* 根据用户id返回token

* @param id

* @return 用户token

*/

String getTokenById(@Param("id")int id);

}

dao层mapper

/p>

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

select u.id id,u.password password, u.username username,r.id rid,r.role_name,r.role_name_CN from authority_user u

left join authority_user_role ur

on ur.user_id=u.id

left join authority_role r

on ur.role_id=r.id

where username=#{username}

insert into authority_user(username,password) values(#{username},#{password})

update authority_user set token=#{token} where id=#{id}

select token from authority_user where id=#{id}

五、entity

AuthorityUser

package cn.**.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;

import org.springframework.security.core.GrantedAuthority;

import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

import java.util.List;

/**

* @ProjectName: springbootSecurity

* @Package: cn.cn.**.security.entity

* @Author: huat

* @Date: 2019/12/12 15:12

* @Version: 1.0

* 创建实体类第一种方式

*/

public class AuthorityUser implements UserDetails {

private int id;

private String username;

private String password;

private List authorityRoles;

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

public List getAuthorityRoles() {

return authorityRoles;

}

public void setAuthorityRoles(List authorityRoles) {

this.authorityRoles = authorityRoles;

}

@Override

@JsonIgnore//忽略此属性 转成json字符串时不进行转换

public Collection extends GrantedAuthority> getAuthorities() {

return authorityRoles;

}

@Override

@JsonIgnore//忽略此属性 转成json字符串时不进行转换

public boolean isAccountNonExpired() {

return true;

}

@Override

@JsonIgnore//忽略此属性 转成json字符串时不进行转换

public boolean isAccountNonLocked() {

return true;

}

@Override

@JsonIgnore//忽略此属性 转成json字符串时不进行转换

public boolean isCredentialsNonExpired() {

return true;

}

/**

* 当前用户是否可用

* @return

*/

@Override

@JsonIgnore//忽略此属性 转成json字符串时不进行转换

public boolean isEnabled() {

return true;

}

}

AuthorityRole

package cn.**.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;

import org.springframework.security.core.GrantedAuthority;

/**

* @ProjectName: springbootSecurity

* @Package: cn.cn.**.security.entity

* @Author: huat

* @Date: 2019/12/12 16:14

* @Version: 1.0

*/

public class AuthorityRole implements GrantedAuthority {

private int rid;

private String roleName;

private String roleNameCN;

public int getRid() {

return rid;

}

public void setRid(int rid) {

this.rid = rid;

}

public String getRoleName() {

return roleName;

}

public void setRoleName(String roleName) {

this.roleName = roleName;

}

public String getRoleNameCN() {

return roleNameCN;

}

public void setRoleNameCN(String roleNameCN) {

this.roleNameCN = roleNameCN;

}

@JsonIgnore//忽略此属性 转成json字符串时不进行转换

@Override

public String getAuthority() {

return roleName;

}

}

Payload

package cn.**.entity;

import java.util.Date;

/**

* @ProjectName: springSecuritySeparate

* @Package: cn.**.entity

* @Author: huat

* @Date: 2019/12/24 13:13

* @Version: 1.0

*/

public class Payload {

private String id;

private T userInfo;

private Date expiration;

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}

public T getUserInfo() {

return userInfo;

}

public void setUserInfo(T userInfo) {

this.userInfo = userInfo;

}

public Date getExpiration() {

return expiration;

}

public void setExpiration(Date expiration) {

this.expiration = expiration;

}

}

六、filter

JwtTokenFilter

package cn.**.filter;

import cn.**.dao.UserDao;

import cn.**.entity.AuthorityRole;

import cn.**.entity.AuthorityUser;

import cn.**.util.JwtUtil;

import cn.**.util.RsaKeyProperties;

import com.fasterxml.jackson.databind.ObjectMapper;

import org.springframework.context.annotation.Configuration;

import org.springframework.security.authentication.AuthenticationManager;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

import org.springframework.security.core.Authentication;

import org.springframework.security.core.AuthenticationException;

import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.io.PrintWriter;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

/**

* @ProjectName: springSecuritySeparate

* @Package: cn.**.filter

* @Author: huat

* @Date: 2019/12/24 17:04

* @Version: 1.0

*/

public class JwtTokenFilter extends UsernamePasswordAuthenticationFilter {

private AuthenticationManager authentication;

private RsaKeyProperties rsaKeyProperties;

private UserDao userDao;

public JwtTokenFilter(AuthenticationManager authentication, RsaKeyProperties rsaKeyProperties,UserDao userDao) {

this.authentication = authentication;

this.rsaKeyProperties = rsaKeyProperties;

this.userDao=userDao;

}

@Override

public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

try {

//从ajax请求流读取参数,转换成AuthorityUser实体类

AuthorityUser authorityUser= new ObjectMapper().readValue(request.getInputStream(), AuthorityUser.class);

//参数是前台传过来的

UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(authorityUser.getUsername(), authorityUser.getPassword());

return authentication.authenticate(authRequest);

} catch (IOException e) {

e.printStackTrace();

try {

response.setContentType("application/json;charset=utf-8");

//返回401状态码 权限不足

response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

//响应流

PrintWriter out=response.getWriter();

//封装返回数据

Map resultMap=new HashMap();

resultMap.put("code",HttpServletResponse.SC_UNAUTHORIZED);

resultMap.put("data","");

resultMap.put("msg","用户名密码错误");

//new ObjectMapper().writeValueAsString(resultMap)将map转成json

out.write(new ObjectMapper().writeValueAsString(resultMap));

out.flush();

out.close();

}catch (Exception outEX){

outEX.printStackTrace();

}

throw new RuntimeException(e);

}

}

@Override

public void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {

AuthorityUser user=(AuthorityUser)authResult.getPrincipal();

/* user.setId(((AuthorityUser)authResult.getPrincipal()).getId());

user.setUsername(authResult.getName());

user.setAuthorityRoles((List) authResult.getAuthorities());*/

String token= JwtUtil.generateTokenExpireInMinutes(user,rsaKeyProperties.getPrivateKey(),24 * 60);

response.setHeader("Authorization","bearer "+token);

try {

//将token保存到数据库当中

int reslut=userDao.updateUserToken(((AuthorityUser)authResult.getPrincipal()).getId(),token);

//如果保存成功给用户返回

if(reslut>0){

response.setContentType("application/json;charset=utf-8");

//返回200状态码

response.setStatus(HttpServletResponse.SC_OK);

//响应流

PrintWriter out=response.getWriter();

//封装返回数据

Map resultMap=new HashMap();

resultMap.put("code",HttpServletResponse.SC_OK);

resultMap.put("data","");

resultMap.put("msg","认证通过");

//new ObjectMapper().writeValueAsString(resultMap)将map转成json

out.write(new ObjectMapper().writeValueAsString(resultMap));

out.flush();

out.close();

}

}catch (Exception outEX){

outEX.printStackTrace();

userDao.updateUserToken(((AuthorityUser)authResult.getPrincipal()).getId(),"");

}

}

}

JwtVerifyFileter

package cn.**.filter;

import cn.**.entity.AuthorityUser;

import cn.**.entity.Payload;

import cn.**.util.JwtUtil;

import cn.**.util.RsaKeyProperties;

import com.fasterxml.jackson.databind.ObjectMapper;

import org.springframework.security.authentication.AuthenticationManager;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

import org.springframework.security.core.Authentication;

import org.springframework.security.core.AuthenticationException;

import org.springframework.security.core.context.SecurityContextHolder;

import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.io.PrintWriter;

import java.util.HashMap;

import java.util.Map;

/**

* @ProjectName: springSecuritySeparate

* @Package: cn.**.filter

* @Author: huat

* @Date: 2019/12/24 18:03

* @Version: 1.0

*/

public class JwtVerifyFileter extends BasicAuthenticationFilter {

private RsaKeyProperties rsaKeyProperties;

public JwtVerifyFileter(AuthenticationManager authenticationManager, RsaKeyProperties rsaKeyProperties) {

super(authenticationManager);

this.rsaKeyProperties = rsaKeyProperties;

}

@Override

public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

// request.getHeader("Authorization")这个括号中的值需要和

// JwtTokenFilter这个类中successfulAuthentication方法中

// response.setHeader("Authorization","bearer "+token);的括号中的第一个值一致

String header = request.getHeader("Authorization");

// header.startsWith("bearer ")这个括号中的值需要和

// JwtTokenFilter这个类中successfulAuthentication方法中

// response.setHeader("Authorization","bearer "+token);的括号中的第二个值加号前一致

if (header == null || !header.startsWith("bearer ")) {

//如果没有登陆提示用户进行登陆

response.setContentType("application/json;charset=utf-8");

//返回403状态码

response.setStatus(HttpServletResponse.SC_FORBIDDEN);

//响应流

PrintWriter out = response.getWriter();

//封装返回数据

Map resultMap = new HashMap();

resultMap.put("code", HttpServletResponse.SC_FORBIDDEN);

resultMap.put("data", "");

resultMap.put("msg", "请登录");

//new ObjectMapper().writeValueAsString(resultMap)将map转成json

out.write(new ObjectMapper().writeValueAsString(resultMap));

out.flush();

out.close();

chain.doFilter(request, response);

} else {

//获取token

String token=header.replace("bearer ","");

//验证token是否正确

Payload payload=JwtUtil.getInfoFromToken(token,rsaKeyProperties.getPublicKey(), AuthorityUser.class);

AuthorityUser user=payload.getUserInfo();

if(null!=user){

UsernamePasswordAuthenticationToken authResult=new UsernamePasswordAuthenticationToken(user.getUsername(),null,user.getAuthorities());

SecurityContextHolder.getContext().setAuthentication(authResult);

chain.doFilter(request, response);

}

}

}

}

七、util

JsonUtil

package cn.**.util;

import cn.**.entity.AuthorityRole;

import cn.**.entity.AuthorityUser;

import com.fasterxml.jackson.core.JsonProcessingException;

import com.fasterxml.jackson.core.type.TypeReference;

import com.fasterxml.jackson.databind.ObjectMapper;

import lombok.extern.slf4j.Slf4j;

import org.apache.catalina.User;

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

import java.util.Map;

/**

* @ProjectName: springSecuritySeparate

* @Package: cn.**.util

* @Author: huat

* @Date: 2019/12/24 10:58

* @Version: 1.0

*/

@Slf4j

public class JsonUtil {

public static final ObjectMapper objectMapper=new ObjectMapper();

/**

* 将对象转为json

* @param object 对象

* @return json

*/

public static String toString(Object object) {

if(null==object){

return null;

}

if(object.getClass()==String.class){

return (String)object;

}

try {

return objectMapper.writeValueAsString(object);

} catch (JsonProcessingException e) {

log.info(object+"序列化出错"+e.getMessage());

e.printStackTrace();

return null;

}

}

/**

* 将json转换成对象

* @param json json字符串

* @param tClass 类

* @param 泛型

* @return 返回对象

*/

public static T toBean(String json,Class tClass){

try {

return objectMapper.readValue(json,tClass);

} catch (IOException e) {

log.info(json+"转对象失败"+e.getMessage());

e.printStackTrace();

return null;

}

}

/**

* 将json转换成集合对象

* @param json json字符串

* @param eClass 类 集合对象

* @param 泛型

* @return 返回对象

*/

public static List toList(String json,Class eClass){

try {

return objectMapper.readValue(json,objectMapper.getTypeFactory().constructCollectionType(List.class,eClass));

} catch (IOException e) {

log.info(json+"转对象失败"+e.getMessage());

e.printStackTrace();

return null;

}

}

/**

* 将json转换成Map对象

* @param json json字符串

* @param kClass 键对象

* @param vClass 值对象

* @param 键的类型

* @param 值的类型

* @return map对象

*/

public static Map toMap(String json,Class kClass,Class vClass){

try {

return objectMapper.readValue(json,objectMapper.getTypeFactory().constructMapType(Map.class,kClass,vClass));

} catch (IOException e) {

log.info(json+"转对象失败"+e.getMessage());

e.printStackTrace();

return null;

}

}

/**

* 复杂类型转换 泛型套泛型

* @param json json字符串

* @param type 返回类型

* @param

* @return 返回对象

*/

public static T nativeRead(String json, TypeReference type){

try {

return objectMapper.readValue(json,type);

} catch (IOException e) {

log.info(json+"转对象失败"+e.getMessage());

e.printStackTrace();

return null;

}

}

public static void main(String[] args) {

//测试nativeRead方法

String json="{\"id\":1,\"username\":\"张三\",\"password\":\"123\",\"authorityRoles\":[{\"rid\":0,\"roleName\":\"张三0\",\"roleNameCN\":null},{\"rid\":1,\"roleName\":\"张三1\",\"roleNameCN\":null},{\"rid\":2,\"roleName\":\"张三2\",\"roleNameCN\":null},{\"rid\":3,\"roleName\":\"张三3\",\"roleNameCN\":null},{\"rid\":4,\"roleName\":\"张三4\",\"roleNameCN\":null}]}\n";

JsonUtil.nativeRead(json,new TypeReference(){});

}

}

JwtUtil

package cn.**.util;

import cn.**.entity.Payload;

import io.jsonwebtoken.Claims;

import io.jsonwebtoken.Jws;

import io.jsonwebtoken.Jwts;

import io.jsonwebtoken.SignatureAlgorithm;

import org.joda.time.DateTime;

import java.security.PrivateKey;

import java.security.PublicKey;

import java.util.Base64;

import java.util.UUID;

/**

* @ProjectName: springSecuritySeparate

* @Package: cn.**.util

* @Author: huat

* @Date: 2019/12/24 12:44

* @Version: 1.0

*/

public class JwtUtil {

private final static String JWT_PAYLOAD_USER_KEY = "user";

/**

* 私钥加密token

*

* @param userInfo 载荷中的数据

* @param privateKey 私钥

* @param expire 过期时间 单位分钟

* @return

*/

public static String generateTokenExpireInMinutes(Object userInfo, PrivateKey privateKey, int expire) {

return Jwts.builder()

.claim(JWT_PAYLOAD_USER_KEY, JsonUtil.toString(userInfo))

.setId(createJTI())

.setExpiration(DateTime.now().plusMinutes(expire).toDate())

.signWith(privateKey, SignatureAlgorithm.RS256)

.compact();

}

/**

* 私钥加密token

*

* @param userInfo 载荷中的数据

* @param privateKey 私钥

* @param expire 过期时间 单位秒

* @return

*/

public static String generateTokenExpireInSeconds(Object userInfo, PrivateKey privateKey, int expire) {

return Jwts.builder()

.claim(JWT_PAYLOAD_USER_KEY, JsonUtil.toString(userInfo))

.setId(createJTI())

.setExpiration(DateTime.now().plusSeconds(expire).toDate())

.signWith(privateKey, SignatureAlgorithm.RS256)

.compact();

}

private static String createJTI() {

return new String(Base64.getEncoder().encode(UUID.randomUUID().toString().getBytes()));

}

/**

* 公钥解析token

* @param token 用户请求的令牌

* @param publicKey 公钥

* @return

*/

private static Jws parserToken(String token, PublicKey publicKey){

return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);

}

/**

* 获取token中的载荷信息

* @param token 用户请求的令牌

* @param publicKey 公钥

* @param userType 用户类型

* @param

* @return 用户信息

*/

public static Payload getInfoFromToken(String token, PublicKey publicKey, Class userType) {

Jws claimsJws = parserToken(token, publicKey);

Claims body = claimsJws.getBody();

Payload payload = new Payload();

payload.setId(body.getId());

payload.setUserInfo(JsonUtil.toBean(body.get(JWT_PAYLOAD_USER_KEY).toString(),userType));

payload.setExpiration(body.getExpiration());

return payload;

}

/**

* 获取token中的载荷信息

* @param token 用户请求的令牌

* @param publicKey 公钥

* @param

* @return 用户信息

*/

public static Payload getInfoFromToken(String token, PublicKey publicKey) {

Jws claimsJws = parserToken(token, publicKey);

Claims body = claimsJws.getBody();

Payload payload = new Payload();

payload.setId(body.getId());

payload.setExpiration(body.getExpiration());

return payload;

}

}

RsaKeyProperties

package cn.**.util;

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

import java.io.IOException;

import java.security.NoSuchAlgorithmException;

import java.security.PrivateKey;

import java.security.PublicKey;

import java.security.spec.InvalidKeySpecException;

/**

* @ProjectName: springSecuritySeparate

* @Package: cn.**.util

* @Author: huat

* @Date: 2019/12/24 15:58

* @Version: 1.0

*/

@Configuration

@ConfigurationProperties("rsa.key")//从配置文件中获取头信息是rsa.key的配置

public class RsaKeyProperties {

private String publicKeyFile;

private String privateKeyFile;

private PublicKey publicKey;

private PrivateKey privateKey;

@PostConstruct//在初始化完成之后执行此方法

public void createRsaKey() throws InvalidKeySpecException, NoSuchAlgorithmException, IOException {

publicKey=RsaUtil.getPublicKey(publicKeyFile);

privateKey=RsaUtil.getPrivateKey(privateKeyFile);

}

public String getPublicKeyFile() {

return publicKeyFile;

}

public void setPublicKeyFile(String publicKeyFile) {

this.publicKeyFile = publicKeyFile;

}

public String getPrivateKeyFile() {

return privateKeyFile;

}

public PublicKey getPublicKey() {

return publicKey;

}

public void setPublicKey(PublicKey publicKey) {

this.publicKey = publicKey;

}

public PrivateKey getPrivateKey() {

return privateKey;

}

public void setPrivateKey(PrivateKey privateKey) {

this.privateKey = privateKey;

}

public void setPrivateKeyFile(String privateKeyFile) {

this.privateKeyFile = privateKeyFile;

}

}

RsaUtil

package cn.**.util;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.nio.file.Files;

import java.security.*;

import java.security.spec.InvalidKeySpecException;

import java.security.spec.PKCS8EncodedKeySpec;

import java.security.spec.X509EncodedKeySpec;

import java.util.Base64;

/**

* @ProjectName: springSecuritySeparate

* @Package: cn.**.util

* @Author: huat

* @Date: 2019/12/24 13:29

* @Version: 1.0

*/

public class RsaUtil {

private final static int DEFAULT_KEY_SIZE=2048;

/**

* 根据密文,生成rea公钥和私钥,并写入指定文件

* @param publicKeyFileName 公钥文件路径

* @param privateKeyFileName 私钥文件路径

* @param secret 盐

* @param keySize 大小

*/

public static void generateKey(String publicKeyFileName,String privateKeyFileName,String secret, int keySize) throws NoSuchAlgorithmException, IOException {

KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance("RSA");

SecureRandom secureRandom=new SecureRandom(secret.getBytes());

keyPairGenerator.initialize(Math.max(keySize,DEFAULT_KEY_SIZE),secureRandom);

KeyPair keyPair=keyPairGenerator.genKeyPair();

//获取公钥并写出

byte[] publicKeyByte=keyPair.getPublic().getEncoded();

publicKeyByte= Base64.getEncoder().encode(publicKeyByte);

writeFile(publicKeyFileName,publicKeyByte);

//获取公钥并写入

byte[] privateKeyByte=keyPair.getPrivate().getEncoded();

privateKeyByte= Base64.getEncoder().encode(privateKeyByte);

writeFile(privateKeyFileName,privateKeyByte);

}

/**

* 获取秘钥

* @param bytes 秘钥的字节形式

* @return

* @throws NoSuchAlgorithmException

* @throws InvalidKeySpecException

*/

private static PrivateKey getPrivateKey(byte[] bytes) throws NoSuchAlgorithmException, InvalidKeySpecException {

bytes=Base64.getDecoder().decode(bytes);

PKCS8EncodedKeySpec spec=new PKCS8EncodedKeySpec(bytes);

KeyFactory keyFactory=KeyFactory.getInstance("RSA");

return keyFactory.generatePrivate(spec);

}

/**

* 获取公钥

* @param bytes 公钥的字节形式

* @return

* @throws NoSuchAlgorithmException

* @throws InvalidKeySpecException

*/

private static PublicKey getPublicKey(byte[] bytes) throws NoSuchAlgorithmException, InvalidKeySpecException {

bytes=Base64.getDecoder().decode(bytes);

X509EncodedKeySpec spec=new X509EncodedKeySpec(bytes);

KeyFactory keyFactory=KeyFactory.getInstance("RSA");

return keyFactory.generatePublic(spec);

}

/**

* 从文件中读取公钥

* @param fileName 公钥保存路径 相对于classpath

* @return 公钥对象

* @throws InvalidKeySpecException

* @throws NoSuchAlgorithmException

*/

public static PublicKey getPublicKey(String fileName) throws InvalidKeySpecException, NoSuchAlgorithmException, IOException {

byte[] bytes=readFile(fileName);

return getPublicKey(bytes);

}

/**

* 从文件中读取公钥

* @param fileName 公钥保存路径 相对于classpath

* @return 私钥对象

* @throws InvalidKeySpecException

* @throws NoSuchAlgorithmException

*/

public static PrivateKey getPrivateKey(String fileName) throws InvalidKeySpecException, NoSuchAlgorithmException, IOException {

byte[] bytes=readFile(fileName);

return getPrivateKey(bytes);

}

private static byte[] readFile(String fileName) throws IOException {

return Files.readAllBytes(new File(fileName).toPath());

}

private static void writeFile(String fileName,byte[] bytes) throws IOException {

File file=new File(fileName);

if(!file.exists()){

file.createNewFile();

}

FileOutputStream fos = new FileOutputStream( fileName);

fos.write(bytes);

fos.close();

}

}

SpringSercurityConfig

package cn.**.util;

import cn.**.filter.JwtTokenFilter;

import cn.**.filter.JwtVerifyFileter;

import cn.**.service.UserService;

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.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.web.cors.CorsConfiguration;

import org.springframework.web.cors.CorsConfigurationSource;

import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;

/**

* @ProjectName: springbootSecurity

* @Package: cn.cn.**.security.util

* @Author: huat

* @Date: 2019/12/14 8:06

* @Version: 1.0

*/

/**

* 开启security注解支持

*

* @EnableWebSecurity EnableGlobalMethodSecurity 方法级授权

* (securedEnabled=true) 开启@Secured 注解过滤权限

* (jsr250Enabled=true)开启@RolesAllowed 注解过滤权限

* (prePostEnabled=true) 使用表达式时间方法级别的安全性 4个注解可用

* @EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled=true,jsr250Enabled=true)

*/

@Configuration

@EnableWebSecurity

public class SpringSercurityConfig extends WebSecurityConfigurerAdapter {

/* @Autowired

UserService1 userService;*/

@Autowired

UserService userService;

@Autowired

private RsaKeyProperties rsaKeyProperties;

/**

* 将security中加密方式注入到spring容器中

*

* @return

*/

@Bean

public PasswordEncoder passwordEncoder() {

return new BCryptPasswordEncoder();

}

/**

* 解决跨域

* @return

*/

@Bean

public CorsConfigurationSource corsConfigurationSource() {

final CorsConfiguration configuration = new CorsConfiguration();

//指定允许跨域的请求(*所有):http://wap.ivt.guansichou.com

configuration.setAllowedOrigins(Arrays.asList("*"));

configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH"));

// setAllowCredentials(true) is important, otherwise:

// The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.

configuration.setAllowCredentials(true);

// setAllowedHeaders is important! Without it, OPTIONS preflight request

// will fail with 403 Invalid CORS request

configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "X-User-Agent", "Content-Type"));

final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

source.registerCorsConfiguration("/**", configuration);

return source;

}

/**

* 将账号密码设置在内存当中

*

* @param auth

* @throws Exception

*/

@Override

public void configure(AuthenticationManagerBuilder auth) throws Exception {

auth

//将UserDetailsService放到容器中

.userDetailsService(userService)

//加密方式放入

.passwordEncoder(passwordEncoder());

}

//前后端分离时候使用

@Override

public void configure(HttpSecurity http) throws Exception {

//释放静态资源,指定资源拦截规则,

// 指定自定义认证页面,指定退出认证配置,csrf(跨域伪造请求)配置

http

.csrf()

.disable()//关闭csrf(跨域伪造请求)

.cors()

.and().servletApi().disable()

.requestCache().disable()

.authorizeRequests()

.antMatchers("/index").hasAnyRole("ADMIN")

.antMatchers("/test").hasRole("TEST")

.anyRequest().authenticated()//其他资源需要认证

.and()

.addFilter(new JwtTokenFilter(super.authenticationManager(),rsaKeyProperties))

.addFilter(new JwtVerifyFileter(super.authenticationManager(),rsaKeyProperties))

.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)//禁用session

;

}

}

八、启动类

package cn.**;

import cn.**.util.RsaKeyProperties;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.boot.context.properties.EnableConfigurationProperties;

/**

* @ProjectName: springSecurity

* @Package: cn.cn.**

* @Author: huat

* @Date: 2019/12/21 8:38

* @Version: 1.0

*/

@SpringBootApplication

@EnableConfigurationProperties(RsaKeyProperties.class)//加载RsaKeyProperties类,以bean形式注入到spring容器中

public class SpringBootApplicationStart {

public static void main(String[] args) {

SpringApplication.run(SpringBootApplicationStart.class,args);

}

}

九、配置文件

spring:

datasource:

driver-class-name: com.mysql.jdbc.Driver

username: root

password: root

url: jdbc:mysql://localhost:3306/security?characterEncoding=UTF-8

mybatis:

type-aliases-package: cn.**.entity

logging:

level:

cn.**.dao: debug

rsa:

key:

#公钥保存地方

publicKeyFile: E:\test\public.pub

#私钥保存地方

privateKeyFile: E:\test\private

十、拦截器

package cn.**.filter;

import cn.**.dao.UserDao;

import cn.**.entity.AuthorityUser;

import cn.**.entity.Payload;

import cn.**.util.JwtUtil;

import cn.**.util.RsaKeyProperties;

import com.fasterxml.jackson.databind.ObjectMapper;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;

import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.PrintWriter;

import java.util.HashMap;

import java.util.Map;

/**

* @ProjectName: springbootSecurityJwtOAuth

* @Package: cn.**.filter

* @Author: huat

* @Date: 2019/12/26 13:18

* @Version: 1.0

*/

@Component

public class LoginInterceptor implements HandlerInterceptor {

@Autowired

private UserDao userDao;

@Autowired

private RsaKeyProperties rsaKeyProperties;

//这个方法是在访问接口之前执行的,我们只需要在这里写验证登陆状态的业务逻辑,就可以在用户调用指定接口之前验证登陆状态了

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

//获取请求头中的信息

String header=request.getHeader("Authorization");

if (null!=header&&header.startsWith("bearer ")){

//获取token

String requestToken=header.replace("bearer ","");

//验证token是否正确

Payload payload= JwtUtil.getInfoFromToken(requestToken,rsaKeyProperties.getPublicKey(), AuthorityUser.class);

AuthorityUser user=payload.getUserInfo();

String token=userDao.getTokenById(user.getId());

if(null!=token&&!"".equals(token)){

if( token.equals(requestToken)){

return true;

}

//如果没有登陆提示用户进行登陆

response.setContentType("application/json;charset=utf-8");

//返回403状态码

response.setStatus(HttpServletResponse.SC_FORBIDDEN);

//响应流

PrintWriter out = response.getWriter();

//封装返回数据

Map resultMap = new HashMap();

resultMap.put("code", HttpServletResponse.SC_FORBIDDEN);

resultMap.put("data", "您的账号在其他地方已登录");

resultMap.put("msg", "请登录");

//new ObjectMapper().writeValueAsString(resultMap)将map转成json

out.write(new ObjectMapper().writeValueAsString(resultMap));

out.flush();

out.close();

return false;

}

}

//如果没有登陆提示用户进行登陆

response.setContentType("application/json;charset=utf-8");

//返回403状态码

response.setStatus(HttpServletResponse.SC_FORBIDDEN);

//响应流

PrintWriter out = response.getWriter();

//封装返回数据

Map resultMap = new HashMap();

resultMap.put("code", HttpServletResponse.SC_FORBIDDEN);

resultMap.put("data", "");

resultMap.put("msg", "请登录");

//new ObjectMapper().writeValueAsString(resultMap)将map转成json

out.write(new ObjectMapper().writeValueAsString(resultMap));

out.flush();

out.close();

return false;

}

}

package cn.**.filter;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Configuration;

import org.springframework.util.ResourceUtils;

import org.springframework.web.servlet.config.annotation.InterceptorRegistry;

import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**

* @Author: huat

* @Date: 2019/7/26 10:18

* @Version: 1.0

*/

@Configuration

public class WebConfigurer implements WebMvcConfigurer {

@Autowired

private LoginInterceptor loginInterceptor;

// 这个方法是用来配置静态资源的,比如html,js,css,等等

@Override

public void addResourceHandlers(ResourceHandlerRegistry registry) {

//super.addResourceHandlers(registry);

}

// 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效

@Override

public void addInterceptors(InterceptorRegistry registry) {

// addPathPatterns("/**") 表示拦截所有的请求,

//excludePathPatterns("/login", "/register"); 表示除了登陆与注册之外,因为登陆注册不需要登陆也可以访问

registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/loginInto", "/login","/login/**","/css/**","/font/**","/img/**","/images/**","/js/**","/lay/**");

//super.addInterceptors(registry); //较新Spring Boot的版本中这里可以直接去掉,否则会报错

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值