Java常用登录认证和授权方式

1、常见方案概述

具体使用那种需要看自己项目的体量和具体的场景。

本案例中提供了五中方案及详细的解决办法,希望对你有帮助。

【方案1-通过session对象共享数据】

用户登录之后将用户的信息和权限信息放入到session中,然后再执行所有的操作中。获取session中存储的信息,如果信息存在就放行,如果信息不存在就不放行。

不足之处:每个方法中都需要通过session取值,冗余较大,不利于维护。

【方案2:通过aop的方式实现】

在springboot中通过@Pointcut注解配置切点,通过aop中的” 通知”实现在执行某方法前或后,先执行指定的通知。

好处:配置后,当我们执行目标方法的时候,通知会自动的执行。

好处:只需要写一份代码,便于维护。

【方案3:通过拦截器实现】

在springboot中配置拦截器,实现请求拦截,也能实现验证和授权功能

【方案4:通过过滤器实现】

过滤器也可以实现登录及权限操作,但是不建议。

【方案5:通过专门的权限框架实现】

    推荐使用:功能齐全,安全性高,不但能够实现验证、授权还可以实现加密、会话管理、缓存等。

shiro权限框架:老牌框架,功能丰富。

spring Security:简单好用,但是必须使用spring框架。

2、方案-通过session共享实现验证和授权方式

2.1、创建springboot工程

Java常用登录认证和授权方式_第1张图片

2.2、创建Employee用户对象

@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
    private String use_rid;
    private String user_name;
}

2.3、创建简单测试类说明

@Controller
public class StudentController {
   //查询数据的时候判断,用户是否已经登录或者是否有权限。
//以前的操作业务如下
@RequestMapping("/showInfoOld")
@ResponseBody
public void showInfoOld(HttpSession session){
    System.out.println("============showInfoOld=============");
    //通过session值获取用户的登录信息和权限信息
    Employee employee=(Employee)session.getAttribute("employee");
    if(employee==null){
        //说明用户没有登录,重定向到登录页面中
    }else{
        //表示用户登录,重定向到你想去的地方
    }
 }
}

3、方案2-通过aop方式实现验证和授权方式

本质:通过spring中通知的方式实现

3.1、通知类型执行顺序及时机

前置通知:执行目标代码前执行

环绕通知:执行目标代码前和代码后都执行

后置通知:执行目标代码后执行

最终通知:在目标方法执行之后执行的通知

异常通知:程序抛出异常后执行

3.2、 创建工程

Java常用登录认证和授权方式_第2张图片

 3.3、导入配置

springboot2.7.10中默认的aop包版本就是1.9.7



    org.aspectj
    aspectjweaver
    1.9.7
    runtime




    org.aspectj
    aspectjrt
    1.9.7
    runtime

3.4、创建“方面”配置切点和通知

注意点1:如果想获取session中的值,直接通过注解注入就行,下面有使用方法

注意点2:案例中,把五中通知类型的方法都放进去了,按照自己的需求使用,单个测试。

@Component
@Aspect
public class EmployeeAspect {
    @Autowired
    HttpSession session;//配置使用session
    @Autowired
    HttpServletRequest request;//配置使用request
    @Autowired
    HttpServletResponse response;//配置使用response

    //配置切点,切点就是告诉程序,那些方法需要使用到某功能
    @Pointcut("execution(* com.txc.springbootpointcut.controller..*.*(..))")
    public void pointCut(){}
   /*
   * 类型:前置通知
   *  配置通知的类型,通知类型有前置通知,后置通知,环绕通知,异常通知,最终通知
   * 如:前置通知就是@Before修饰,在执行你的方法之前,先执行我指定的方法
   * 通知的本质就是:拦截器
   * JoinPoint能够获取我们执行的是哪个方法
    * @Before("pointCut()"):pointCut()是上面定义的切点方法
   * */
    @Before("pointCut()")
    public void before(JoinPoint joinPoint) throws IOException {
        System.out.println("=============执行了前置通知===========");
        Employee employee=(Employee) session.getAttribute("employee");
        if(employee!=null){
            //放行
        }else{
            //重定向,可以通过request或response等重定向
            response.sendRedirect("/showInfoOld");
        }
    }

    /*
    * 类型:环绕通知
    * */
    @Around("pointCut()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("===========环绕通知开始=============");
        proceedingJoinPoint.proceed();
        System.out.println("===========环绕通知结束=============");
    }

    /*
    * 最终通知
    * */
    @After("pointCut()")
    public void after(JoinPoint joinPoint){
        //获取方法名
        String methodName = joinPoint.getSignature().getName();
        //获取方法的参数
        Object[] args = joinPoint.getArgs();
        //获取username
        System.out.println("==========后置通知执行=========="+session.getAttribute("username"));
    }

    /*
    * 类型:异常通知
    * 时机:发生异常的时候执行的方法
    * */
    @AfterThrowing(value = "pointCut()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Exception e) {
        System.out.println("=====异常信息=====" + e.getMessage());
    }

    /*
    * 类型:后置通知
    * */
    @AfterReturning("pointCut()")
    public void afterReturning(){
        System.out.println("=============后置通知=============");
    }
}

3.5、创建测试类测试目标方法,通知自动执行

StudentController中showInfoNew方法执行的时候,会自动触发aop,因为aop中定义了切点如下。

@Pointcut("execution(* com.txc.springbootpointcut.controller..*.*(..))")

@Controller
    public static class StudentController {
        //我们可以通过aop的思想实现,更加的简便,利于维护
        @RequestMapping("/showInfoNew")
        @ResponseBody
        public void showInfoNew(HttpSession session){
            session.setAttribute("username","晓春");
            System.out.println("=======执行了showInfoNew方法========");
        }
    }
}

3.6、测试结果

Java常用登录认证和授权方式_第3张图片

4、方案3-通过拦截器方式

本质:需要通过springboot整合使用拦截器

 重点:Springboot中使用拦截器需要实现WebMvcConfigurer 接口,重写addInterceptors方法,并注入。

4.1、环境说明

案例中使用IDEA+springboot2.7.9+jdk1.8+mysql版本开发

4.2、创建工程

选择springboot版本+springbweb依赖

Java常用登录认证和授权方式_第4张图片

4.3、项目创建成功后包依赖如下


    org.springframework.boot
    spring-boot-starter-parent
    2.7.9
     


    
        org.springframework.boot
        spring-boot-starter
    

    
        org.springframework.boot
        spring-boot-starter-test
        test
    

    
        org.springframework.boot
        spring-boot-starter-web
    

    
        org.projectlombok
        lombok
        1.16.14
    

4.4、自定义类实现拦截器HandlerInterceptor 接口

案例说明:访问资源的时候拦截器实现获取session中user的值,如果值不存在,通过request或response就重定向

如果值存在就放行

preHandle:返回值为false不放行,返回值为true表示放行

public class UserInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("===============拦截器===============");
        //从session中获取user的信息
        User user = (User) request.getSession().getAttribute("user");
        //判断用户是否登录
        if (null == user) {
            response.sendRedirect("user/error");//可以写你想重定向的路径
            //request.setAttribute("msg", "请先登录");
            //request.getRequestDispatcher("/login.html").forward(request, response);
            return false;
        }
        return true;
    }
}

4.5、将自定义拦截器注入到系统中

需要实现WebMvcConfigurer 类重写addInterceptors方法

重点:自定义配置类InterceptorConfig 需要使用注解@Component进行实例,否则不生效

addPathPatterns:设置拦截器拦截的请求地址,/**表示拦截所有的请求

excludePathPatterns:设置拦截器不想拦截的地址,"/user/login","/error"表示不拦截的地址

registry.addInterceptor:将自定义拦截器注入进WebMvcConfigurer配置中

 

@Component
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        String[] addPathPatterns = {//拦截所有请求
                "/**"
        };
        String[] excludePathPatterns = {//设置不想拦截的路径
                "/user/login","/error"
        };
        registry.addInterceptor(new UserInterceptor()).addPathPatterns(addPathPatterns).excludePathPatterns(excludePathPatterns);
    }
}

4.6、启动类代码

@SpringBootApplication
@ComponentScan(basePackages ="com.txc")
public class SpringinterceptorApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringinterceptorApplication.class, args);
    }
}

4.7、创建测试类

说明:此时当我们访问下面的test方法时候,会优先执行拦截器InterceptorConfig中的addInterceptors方法

@Controller
public class UserController {
    @RequestMapping("/test")
    public String test(){
        System.out.println("=========test===========");
        return "";
    }
}

5、方案4-通过过滤器Filter实现

创建springboot工程,导入springweb开发包

5.1、自定义过滤器

doFilter:中写了一个常用的登录校验,如果正在登录就放行,如果登录过放行,如果没有登录就重定向。

filterChain.doFilter(servletRequest, servletResponse):表示放行

public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("=======过滤器执行========");
        HttpServletRequest request=(HttpServletRequest)servletRequest;
        HttpServletResponse response=(HttpServletResponse)servletResponse;
        HttpSession session=request.getSession();
        //获取当前的请求地址
        String servletpath=request.getServletPath();
        System.out.println(servletpath);
        if(servletpath.equals("/login.do") || servletpath.equals("/login.html")){
            filterChain.doFilter(servletRequest, servletResponse);
        }else{
            String username=(String)session.getAttribute("username");
            if(username==null || username.equals("")){
                response.sendRedirect("login.html");
            }else{
                filterChain.doFilter(servletRequest, servletResponse);
            }
        }
        filterChain.doFilter(servletRequest,servletResponse);
    }
    @Override
    public void destroy() {
    }
}

5.2、向spring容器中注入Filter

@Component
public class FilterConfig {
    //注册三大组件--Filter
    @Bean
    public FilterRegistrationBean myFilter(){
        FilterRegistrationBean filter=new FilterRegistrationBean();
        filter.setFilter(new MyFilter());
        // /*表示过滤所有请求   /myfilter:过滤指定请求
        filter.setUrlPatterns(Arrays.asList("/*","/myfilter"));
        return filter;
    }
}

5.3、拦截器和过滤器比较

应用场景不同:

拦截器:更多用于性能分析、日志记录、权限检查、登录验证、处理cookie、本地化、国际化

过滤器:通用对请求的URL进行过滤,对敏感词汇进行过滤、设置字符编码、压缩响应信

执行的时机不同:

    拦截器:进入Controller之前进行预处理的,Controller 中渲染了对应的视图之后请求结束

    过滤器:在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后

过滤器在拦截器之前执行

依赖不同:

  拦截器:不依赖tomcat容器,可以单独使用

  过滤器:是Servlet的一部分,有依赖性

实现原理不同:

  拦截器:使用动态代理等技术

  过滤器:使用xml解析和servlet容器等技术

6、方案5-通过shiro框架实现验证和授权

如下案例实现登录、校验、授权、动态菜单管理+数据库设计

https://blog.csdn.net/tangshiyilang/article/details/130089485

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(java项目解决方案,java,spring,boot,spring)