SpringBoot整合SpringSecurity+Jwt

1 篇文章 0 订阅
1 篇文章 0 订阅


前言

最近公司开启了一个新项目,登录和权限认证这一块我准备采用SpringSecurity+Jwt令牌来完成,下面是简单记录前期整合的部分,因为自己已经对这一块进行了一段时间的学习,文章只是对自己开发功能的一个记录,这两者没有分开细说,直接整合,只对一些必要代码进行补充。
PS:本来准备使用SpringSecurityOauth2.0的,仔细的考虑了一下系统的功能,虽然是分布式系统,但是主要还是自己系统内部的访问为主,并不对接三方,相比于SpringSecurityOauth2.0较为复杂的配置(主要还是自己不怎么熟0.0)SpringSecurity配置更加简单,所以直接上!


提示:以下是本篇文章正文,内容仅供参考

一、引入jar包

<!-- 具体版本自己选择 -->
	 <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-security</artifactId>
     </dependency>
     <dependency>
         <groupId>io.jsonwebtoken</groupId>
         <artifactId>jjwt</artifactId>
         <version>${version}</version>
     </dependency>

二、使用步骤

1.流程图

先看一张流程分析图:
在这里插入图片描述
主要流程简单概括如下:
1、用户提交用户名密码,SpringSecurity用UsernamePasswordAuthenticationToken封装用户名密码
继承关系如下图:
在这里插入图片描述

2、提交认证管理器
3、认证成功以后返回一个Authentication对象
4、Authentication对象填充到SecurityContextHolder安全上下文容器
5、根据Authentication生成token返回

2.工程目录

在这里插入图片描述
说明,因为前后端分离,没有配置登录页和跳转之类的,全部交由前端完成,所以mvc的配置是没有的。

三、详细代码

config类


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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author zhangqingfeng
 * @version 1.0
 * @email zhangqingfeng95@icloud.com
 * @date 2021/4/19 11:12
 */
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	//SpringSecurity要求在定义认证逻辑是Spring容器内必须要有一个密码编码器,所以要提前注入一个Bean
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    
	//低版本的时候认证管理器直接使用Autowired是可以注入的,
	//但是这个版本一直报空指针一场,随后百度了一下,要自己重写一下方法才行
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests()
                .antMatchers("/userLogin/login").permitAll()
                .anyRequest().authenticated()
                .and()
                ;
    }
}

entity类

1、JwtAuthorization

/**
* 这个类是用来封装一些额外的请求参数到UsernamePasswordAuthenticationToken一起认证的,
* 因为前期整合,暂时并没有用到,只是预留在此
*/
public class JwtAuthorization extends UsernamePasswordAuthenticationToken {
    public JwtAuthorization(Object principal, Object credentials) {
        super(principal, credentials);
    }

    public JwtAuthorization(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
        super(principal, credentials, authorities);
    }
}

2、user类


/**
* 此类同理,用来扩展信息,暂时只用到用户名密码和权限等字段
*/
public class User implements UserDetails {

    private String username;
    private String password;
    private List<GrantedAuthority> grantedAuthorities;

    public User(String username, String password, List<GrantedAuthority> grantedAuthorities) {
        this.username = username;
        this.password = password;
        this.grantedAuthorities = grantedAuthorities;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public List<GrantedAuthority> getGrantedAuthorities() {
        return grantedAuthorities;
    }

    public void setGrantedAuthorities(List<GrantedAuthority> grantedAuthorities) {
        this.grantedAuthorities = grantedAuthorities;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.grantedAuthorities;
    }

    @Override
    public String getPassword() {
        return this.password;
    }

    @Override
    public String getUsername() {
        return this.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;
    }
}

controller类

@RestController
@CrossOrigin
@RequestMapping("/userLogin")
public class UserController {

	//认证管理器
    @Autowired
    private  AuthenticationManager authenticationManager;
    @RequestMapping("/login")
    public Result login(@RequestParam String username, @RequestParam String password){
        String token = SecurityUtil.login(username, password,authenticationManager);
        return new Result(true, StatusCode.OK,"登录成功!",token);
    }
}

关键类:SecurityUtil

package com.kangjiu.utils;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.context.annotation.ComponentScan;
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.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zhangqingfeng
 * @version 1.0
 * @email zhangqingfeng95@icloud.com
 * @date 2021/4/19 14:31
 */
@Configuration
@ComponentScan
public class SecurityUtil implements Serializable {

    /**
     * 有效期12小时
     */
    private static final long EXPIRE_TIME = 12 * 60 * 60 * 1000;

    /**
     * 密钥
     */
    private static final String SECRET = "abcdefg";

    /**
     * 创建时间
     */
    private static final String CREATED = "created";

    public static String login(String username, String password, AuthenticationManager authenticationManager){
    //这里封装用户名密码
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username,password);
        //这里认证管理器最终会找到我们下面写的UserDetailService
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        return generateToken(authenticate);
    }

    /**
     * 生成令牌
     * 用户名权限等信息封装成令牌,后期再网关或者aop中解析
     * @param authentication 用户
     * @return 令牌
     */
    public static String generateToken(Authentication authentication) {
        Map<String, Object> claims = new HashMap<>(3);
        claims.put("USERNAME", SecurityUtil.getUsername(authentication));
        claims.put(CREATED, new Date());
        claims.put("AUTHORITIES", authentication.getAuthorities());
        return generateToken(claims);
    }

    /**
     * 从数据声明生成令牌
     *
     * @param claims 数据声明
     * @return 令牌
     */
    private static String generateToken(Map<String, Object> claims) {
        Date expirationDate = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        return Jwts.builder().setClaims(claims).setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, SECRET).compact();
    }



    /**
     * 获取用户名
     * @return
     */
    public static String getUsername(Authentication authentication) {
        String username = null;
        if(authentication != null) {
            Object principal = authentication.getPrincipal();
            if(principal != null && principal instanceof UserDetails) {
                username = ((UserDetails) principal).getUsername();
            }
        }
        return username;
    }

    public static Authentication getAuthentication() {
        if(SecurityContextHolder.getContext() == null) {
            return null;
        }
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return authentication;
    }

}

service类

@Service
public class UserDetailServiceImpl implements UserDetailsService {

	//密码编码器
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
    //这里后期要匹配数据库,从数据库里查询用户名密码,调用封装成User对象,和Authentication相比较
        System.out.println("username为:"+s);
        String username = "admin";
        String password = "admin";
        return new User(username,passwordEncoder.encode(password), AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }
}

四、启动项目测试

在这里插入图片描述


五、总结

以上就是我在项目里对SpringSeurity的整合了,如果有不对的地方,评论区请指正,谢谢!

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值