spring security 从零开始搭建

1.引入

复制代码
<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.3</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>2.6.6</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
    </dependencies>
复制代码

 

2.配置

复制代码
package com.cj.system.config;

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;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .formLogin() //表单登陆 1
                .and() //2
                .authorizeRequests() //下面的都是授权的配置 3
                .antMatchers("/admin/system/index/login").anonymous()//不需授权就可以访问的
                .anyRequest().authenticated(); //访问任何资源都需要身份认证 5
    }
}
复制代码

配置完成之后登录的效果

默认用户名为user

 

 

3 修改登录名,密码为数据库用户名,密码

3.1 配置里增加

复制代码
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder(){
    return new MyMD5Password();
}
复制代码

3.2 增加加密函数

复制代码
public class MyMD5Password implements PasswordEncoder {
    @Override
    public String encode(CharSequence rawPassword) {
        return MD5.encrypt(rawPassword.toString());
    }
    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
//        System.out.println(rawPassword);
//        System.out.println(MD5.encrypt(rawPassword.toString()));
//        System.out.println(encodedPassword);
        if(MD5.encrypt(rawPassword.toString()).equals(encodedPassword)){
            return true;
        }
        return false;
    }
}
复制代码

 

3.3 登录修改封装对象

/*start插入security*/
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginVo.getUsername(),loginVo.getPassword());
//authenticationManager 对象
Authentication authenticate = authenticationManager.authenticate(authenticationToken);
if(authenticate == null){
    throw new RuntimeException("登录失败");
}
MyUserDetail userDetail = (MyUserDetail) authenticate.getPrincipal();

 

4. 过滤器配置

4.1 配置

复制代码
 @Override
 protected void configure(HttpSecurity http) throws Exception {
     http
             .csrf().disable()
             .formLogin() //表单登陆 1
             .and() //2
             .authorizeRequests() //下面的都是授权的配置 3
             .antMatchers("/admin/system/index/login").anonymous()
             .anyRequest().authenticated(); //访问任何资源都需要身份认证 5
       //添加过滤器
     http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
       //添加异常处理器
       http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
               .accessDeniedHandler(accessDeniedHandler);
 }
复制代码

4.2 过滤器代码

复制代码
package com.cj.system.filter;

import com.cj.common.util.JwtHelper;
import com.cj.model.system.SysToken;
import com.cj.model.system.SysUser;
import com.cj.system.custom.MyUserDetail;
import org.springframework.beans.factory.annotation.Autowired;
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.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

@Component
public class JwtFilter extends OncePerRequestFilter {


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = request.getHeader("token");
        if(!StringUtils.hasText(token)){
            filterChain.doFilter(request,response);
            return;
        }

        String userId = JwtHelper.getUserId(token);
        String username = JwtHelper.getUsername(token);

        if(userId == null){
            throw new RuntimeException("token非法");
        }
        //获取信息
        //TODOredis

        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\userDetail.txt"));

        MyUserDetail myUserDetail = null;
        try {
            myUserDetail = (MyUserDetail)objectInputStream.readObject();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        if(myUserDetail == null){
            throw new RuntimeException("用户未登录");
        }

        //UsernamePasswordAuthenticationToken
        //TODO权限
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(myUserDetail, null, null);

        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        filterChain.doFilter(request,response);
    }
}
复制代码

 

4.3 效果

 

 

4.4 ps:获取的是头信息的token 使用 request.getHeader('token')

5 配置权限

5.1 在config中配置

@EnableGlobalMethodSecurity(prePostEnabled = true)

 

5.2 在需要验证的方法上加注解

@PreAuthorize("hasAuthority('bnt.sysRole.list')")

 

5.3 修改userdetail

复制代码
 private List<String> permissions;
 @Override
 public Collection<? extends GrantedAuthority> getAuthorities() {
     List<GrantedAuthority> newList = new ArrayList<>();
     for(String permission:permissions){
         newList.add(new SimpleGrantedAuthority(permission));
     }
     return newList;
 }
复制代码

 

5.4 修改loaduser 加上权限

 List<String> permissions = sysMenuService.getUserBottonList(sysUser.getId());

 

5.5 修改filter

UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(myUserDetail, null, myUserDetail.getAuthorities());

 

6 异常配置

6.1 配置

//添加异常处理器
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
        .accessDeniedHandler(accessDeniedHandler);

6.2 权限异常

public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        Result result = new Result(403,"授权失败",null);
        System.out.println(accessDeniedException);
        WebUtil.renderString(response, JSON.toJSONString(result));
    }
}

 

6.3 授权异常

复制代码
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
    /**
     * 认证失败
     * @param request
     * @param response
     * @param authException
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        Result result = new Result(401,"用户认证失败请重新登录",null);
        WebUtil.renderString(response,JSON.toJSONString(result));
    }
}
复制代码

 

posted @   写代码的小哥哥  阅读(103)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示