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

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

  •  
  •   yanyueio · 163 天前 · 1840 次点击
    这是一个创建于 163 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

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

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

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

    16 条回复    2020-02-02 12:44:30 +08:00
    tairan2006
        1
    tairan2006   163 天前 via Android
    自己写注解能有多麻烦…
    tangtj
        2
    tangtj   163 天前
    启动后从容器获取`RequestMappingHandlerMapping`,获取所有`HandlerMethod`拿到自己标记了注解的方法.
    实现`AccessDecisionVoter`接口,在逻辑内对访问的 url 做判断实现.
    把实现配置到`accessDecisionManager()`
    k9990009
        3
    k9990009   163 天前 via Android
    自定义注解鉴权,就是启动的时候查找所有 controller,然后找到所有标记了你自定义的注解的 url 及对应所需的角色权限,加个拦截器检查就完了。简单点,你注解也不用写了,就请求 url 加前缀,拦截器根据前缀处理。
    yanyueio
        4
    yanyueio   163 天前
    @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   163 天前
    @yanyueio 我大概记得以前类似这么用拦截器干过,在 preHandle 里去取对应方法的 RequiredPermission 注解,如果有有就判断里面提供的权限。没有再配置 SpringSercurity 了。不过那些都是些小项目,基本上权限管理,登陆验证,token 生成存储与验证之类的都是土法炼钢一整套
    jorneyr
        6
    jorneyr   163 天前
    1. 实现自定义注解并在 Spring 中生效,可以参考 https://qtdebug.com/spring-core-aspectj-custom-annotation
    2. 在注解中获取当前用户的信息,该判断登录的判断登录,该判断权限的判断权限即可,如果不满足条件,未登录的跳转到登录页面,登录了的权限不够进行提示
    qinxi
        7
    qinxi   163 天前   ❤️ 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   163 天前
    自己在拦截器里面控制不香吗?多个拦截器,定义顺序,不同的路径不同的权限。Spring security 对我来说有点重!
    zhang5388137
        9
    zhang5388137   163 天前
    这个不就是 自定义的拦截器 里面自定义的注解吗
    hantsy
        10
    hantsy   163 天前
    过去多年的经验,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   163 天前
    @qinxi 这个大致和我最初想的差不多了。
    @hantsy 您这么一说,貌似也是这么个设计思想,当初没想到是业务代码解耦。

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

    再次感谢。
    hantsy
        12
    hantsy   163 天前
    @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   162 天前
    @hantsy #12 因为我使用到自定义以及多种认证方式结合的登录,所以我的 filter,provider,token,handle 都是自己实现的.

    就算是使用默认实现,也是同样的流程.区别在于谁实现的问题
    abcbuzhiming
        14
    abcbuzhiming   162 天前
    Spring security 实现的非常学术化,很多地方很死板,尤其是对登录处理器的配置,一点都不如 shiro 灵活,我不建议用这个库,甚至 spring 自己的社区用的都是 shiro
    hantsy
        15
    hantsy   162 天前
    @abcbuzhiming 当你要支持各种协议的时候,你就发现 Shiro 多少简陋。
    hantsy
        16
    hantsy   162 天前
    @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 集成。
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3028 人在线   最高记录 5168   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 12:37 · PVG 20:37 · LAX 05:37 · JFK 08:37
    ♥ Do have faith in what you're doing.