V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yanyueio
V2EX  ›  程序员

Spring(Boot) Security 拦截登录封装问题咨询请教

  •  
  •   yanyueio · 2020-02-01 12:02:15 +08:00 · 3356 次点击
    这是一个创建于 1539 天前的主题,其中的信息可能已经有所发展或是发生改变。

    大佬们,请问您有做过类似 @login 这类拦截登录的封装么?

    例如某个 RequestMapping(URL) 方法上,只要加了这个注解,它就自动处理拦截,包括 next 跳转等工作?

    不晓得我的表述是否到位,大概的意思应该说了,总而言之:

    • @login 必须登录才能访问
    • @admin 必须管理员才能访问

    个人觉得 Spring Security 这类重写 WebSecurityConfigurerAdapter 的方式实在太老土且麻烦。

    大佬们请不吝指点一下(秀出您超 man 的肌肉吧)。

    因为有点赶时间,如果有现成的最好。。。做伸手党实在不好意思啦

    16 条回复    2020-02-02 12:44:30 +08:00
    tairan2006
        1
    tairan2006  
       2020-02-01 13:22:43 +08:00 via Android
    自己写注解能有多麻烦…
    tangtj
        2
    tangtj  
       2020-02-01 13:22:59 +08:00
    启动后从容器获取`RequestMappingHandlerMapping`,获取所有`HandlerMethod`拿到自己标记了注解的方法.
    实现`AccessDecisionVoter`接口,在逻辑内对访问的 url 做判断实现.
    把实现配置到`accessDecisionManager()`
    k9990009
        3
    k9990009  
       2020-02-01 14:01:28 +08:00 via Android
    自定义注解鉴权,就是启动的时候查找所有 controller,然后找到所有标记了你自定义的注解的 url 及对应所需的角色权限,加个拦截器检查就完了。简单点,你注解也不用写了,就请求 url 加前缀,拦截器根据前缀处理。
    yanyueio
        4
    yanyueio  
    OP
       2020-02-01 14:33:12 +08:00
    @k9990009 我理解您的思路大致是:

    ```java
    //在 preHandle(HttpServletRequest request) 里面
    //拦截器处理用户权限
    String uri = request.getRequestURI();
    if (uri.startsWith("/admin") && !uri.startsWith("/admin/login")) {
    //这里先不处理登录后的跳转问题
    response.sendRedirect(request.getContextPath() + "/admin/login");
    return false;
    }
    ```

    然而,这样做的话,SpringSecurity 里面还配置么?即 authroizeReqests() 那套逻辑。

    ```java
    config(HttpSecurity http) {
    http.authorizeRequests().antMatchers("/admin/**").accsess("hasRole('ADMIN')")
    .and() .... //blabla
    }
    ```

    我这边权鉴还是在 SpringSecurity 逻辑里面,具体说就是 `AuthenticationManagerBuilder`,用的 jdbc auth 那套处理的 user, role,之后配置 config(HttpSecurity http) 这里的时候就发现这样配置 Mapping URL 的逻辑不利于后续扩展,比如后面又增加了其他正则类型的 URL,**写完 Controller 就要过来改这边**。

    而自己写拦截器只判断 URL 这一边,那么 SpringSecurity 那套不配置啦?如果配置,那么是不是比原来功夫更多了。

    还是感谢您分享自己的经验。
    kanezeng
        5
    kanezeng  
       2020-02-01 16:35:06 +08:00
    @yanyueio 我大概记得以前类似这么用拦截器干过,在 preHandle 里去取对应方法的 RequiredPermission 注解,如果有有就判断里面提供的权限。没有再配置 SpringSercurity 了。不过那些都是些小项目,基本上权限管理,登陆验证,token 生成存储与验证之类的都是土法炼钢一整套
    jorneyr
        6
    jorneyr  
       2020-02-01 17:00:07 +08:00
    1. 实现自定义注解并在 Spring 中生效,可以参考 https://qtdebug.com/spring-core-aspectj-custom-annotation
    2. 在注解中获取当前用户的信息,该判断登录的判断登录,该判断权限的判断权限即可,如果不满足条件,未登录的跳转到登录页面,登录了的权限不够进行提示
    qinxi
        7
    qinxi  
       2020-02-01 17:54:37 +08:00   ❤️ 1
    关键流程:

    1. 开启注解拦截
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled=true)

    2. 在 AuthenticationProvider 中给 AuthenticationToken 增加 GrantedAuthority

    3.方法或类上增加 @PreAuthorize("hasAuthority(T(com.xxx.enums.Role).ADMIN.name())") 或者通过 HttpSecurity#authorizeRequests 配置
    zhaoyou
        8
    zhaoyou  
       2020-02-01 18:18:22 +08:00
    自己在拦截器里面控制不香吗?多个拦截器,定义顺序,不同的路径不同的权限。Spring security 对我来说有点重!
    zhang5388137
        9
    zhang5388137  
       2020-02-01 18:24:38 +08:00
    这个不就是 自定义的拦截器 里面自定义的注解吗
    hantsy
        10
    hantsy  
       2020-02-01 18:37:45 +08:00
    过去多年的经验,Annoations 方式不是很好用。Java EE 规范中是这样为主。

    对于 Http 访问,URI 拦截才是最简单的,集中配置更简单。

    Spring Security 支持三种 Annotations。
    1. Secured
    2. PreAuthorize, PostAuthorize
    3. Java EE 兼容 Annotations

    从系统设计的角度,定义一个自己的 Adapter 集中处理安全配置。

    1. 将 Security 配置从业务代码分离出来,也是一种解耦吧。
    2. 可以使用编程方式配置,也就是说安全属性可以写到数据库或者其它地方,并且可以动态配置(中国人不是喜欢界面配置权限,这种方式很容易实现)。
    3. 更容易写测试,测试逻辑时完全可以将安全配置 Disable 掉(如果你写测试的话)。
    yanyueio
        11
    yanyueio  
    OP
       2020-02-01 18:59:57 +08:00
    @qinxi 这个大致和我最初想的差不多了。
    @hantsy 您这么一说,貌似也是这么个设计思想,当初没想到是业务代码解耦。

    感谢众位大佬点播,个人感觉在 @qinxi 的基础上再封装一次是可行的。

    再次感谢。
    hantsy
        12
    hantsy  
       2020-02-01 19:26:19 +08:00
    @qinxi
    1. 第一步中,如果是使用最新 Spring Boot,不要添加 @EnableWebSecurity,Spring Boot AutoConfiguration 会对添加默认 Spring Security 配置。
    1. 添加 @EnableWebSecurity 会破坏默认配置。
    2. 而一个普通 @Configuration WebSecurityConfigurerAdapter bean 会在默认配置基础上添加自己的配置。

    类似在 Spring Boot 中,@EnableWebMVC, @Enable***repsitories 都不要使用。配置自己项目时,参阅 SpringBoot 文档,大部分默认配置可以通过修改 applicaiton.properties|yaml 简单的完成。
    2. 最简单的实现,只需要配置一个 UserDetailsService Bean。除非你想改变 Anthentication 内部机制,才需要自己的 AnthenticationProvider。
    qinxi
        13
    qinxi  
       2020-02-01 23:01:38 +08:00
    @hantsy #12 因为我使用到自定义以及多种认证方式结合的登录,所以我的 filter,provider,token,handle 都是自己实现的.

    就算是使用默认实现,也是同样的流程.区别在于谁实现的问题
    abcbuzhiming
        14
    abcbuzhiming  
       2020-02-02 11:48:25 +08:00
    Spring security 实现的非常学术化,很多地方很死板,尤其是对登录处理器的配置,一点都不如 shiro 灵活,我不建议用这个库,甚至 spring 自己的社区用的都是 shiro
    hantsy
        15
    hantsy  
       2020-02-02 12:32:25 +08:00
    @abcbuzhiming 当你要支持各种协议的时候,你就发现 Shiro 多少简陋。
    hantsy
        16
    hantsy  
       2020-02-02 12:44:30 +08:00
    @qinxi Spring Security 5 内部支持 Http Basic, Spring Session (一种 Token 机制),X509 安全证书, user/password login form, 和 OAuth2/OIDC 协议,这个衍生的子协议太多了,内部支持一些实现,包括 twitter,facebook, google, okta, github 等,其它的 Oauth2/Oidc 兼容协议一样可以配置(复杂一点)。

    对于多种安全配置,我倾向于使用成熟方案,比如 Keycloak,还有 Cloud 服务,比如 Okta,Auth0. 可以轻松配置集成多种登录一起,比如 2fa, otp, 普通的 user/password , social ( OAuth2 ) 等,这些服务都可以很好与 Spring Security 5 集成。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1005 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 22:52 · PVG 06:52 · LAX 15:52 · JFK 18:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.