Grails Spring 安全性

Posted

技术标签:

【中文标题】Grails Spring 安全性【英文标题】:Grails Spring Security 【发布时间】:2020-07-01 20:58:44 【问题描述】:

我正在尝试创建一个登录页面,该页面将根据用户拥有的角色登录到特定帐户,但由于某种原因,spring security 永远不会识别用户名和密码

这里是登录控制器

package login_page

导入 grails.plugin.springsecurity.userdetails.DefaultPostAuthenticationChecks 导入 org.springframework.security.access.annotation.Secured

@Secured('permitAll') 类 LoginController 扩展 grails.plugin.springsecurity.LoginController

PersonService personService

def index() 
    if (isLoggedIn()) 
        redirect uri: conf.successHandler.defaultTargetUrl
    
    else 
        redirect action: 'auth', params: params
    

def auth() 

    def conf = getConf()

    if (isLoggedIn()) 
        redirect uri: conf.successHandler.defaultTargetUrl
        return
    

    String postUrl = request.contextPath + conf.apf.filterProcessesUrl
    render view: 'index', model: [postUrl: postUrl,
                                 rememberMeParameter: conf.rememberMe.parameter,
                                 usernameParameter: conf.apf.usernameParameter,
                                 passwordParameter: conf.apf.passwordParameter,
                                ]

成功的 uri 是 /person/LoginPage

LoginPage 方法是这样的

   @Secured(['ROLE_USER','ROLE_ADMIN','ROLE_SUPERADMIN'])
def LoginPage() 
      refreshCurrentUser()
    if (currentPerson == null) 
        notFound()
    else 
        if(currentPerson.getAuthorities()[0].getAuthority()=="ROLE_SUPERADMIN")
            redirect(controller:'superAdmin', action: 'superAdminShow', id: currentPerson.id)
        
       else if(currentPerson.getAuthorities()[0].getAuthority()=="ROLE_ADMIN")
            redirect(controller:'admin', action: 'adminShow', id: currentPerson.id)
        
        else if(currentPerson.getAuthorities()[0].getAuthority()=="ROLE_USER")
            redirect(action: 'show', id: currentPerson.id)
        
    

【问题讨论】:

另外,伙计们,我有一个带有表单操作的自定义登录页面:- /login/authenticate spring 对安全性真的很挑剔,如果在声明 spring-boot 时它在路径中,它会启动,阻止一切,因为它没有配置。 是的,这就是为什么我要覆盖 index 和 auth 方法,但由于某种原因,它无法识别我为 person 对象拥有的用户名和密码 我的观点是,当安全 jar 在路径中,并且没有进行安全更改时,它通常会返回权限错误,直到设置安全,这是我的 spring-boot 经验 所以我们可以通过提供用户名和密码凭据来设置安全性吗? 【参考方案1】:

这是一个非常简单的安全配置,我为一个愚蠢的演示而即时组合在一起(一个反应式 Java Rest API)。我绝不是安全专家,但它可以让您了解所涉及的事情。

import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;

import XXXXXXXX.Permissions;
import XXXXXXXXX.UserPermissions;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity.AuthorizeExchangeSpec;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import reactor.core.publisher.Mono;


@Configuration
@EnableWebFluxSecurity
public class ApiSecurityConfiguration implements ReactiveAuthenticationManager

    @Autowired
    Permissions permissions;
    @Autowired
    RedisTemplate<String, Object> redisCache;

    private static final Logger logger = LoggerFactory.getLogger(ApiSecurityConfiguration.class);
    private UserPermissions userPermissionTable;

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) 
        AuthorizeExchangeSpec authorize;
        http.formLogin().disable();
        http.csrf().disable();
        http.logout().disable();å
        http.httpBasic().disable();
        http.httpBasic().
        authenticationManager(this::authenticate);
        authorize = http.authorizeExchange();
        authorize.anyExchange().access(this::check);

        return http.build();
    

    private Mono<AuthorizationDecision> check(Mono<Authentication> authentication, AuthorizationContext context) 
        return authentication.map(a ->this.checkAuthorizations(a, context)).map(granted -> new AuthorizationDecision(granted));
    

    private boolean checkAuthorizations(Authentication a, AuthorizationContext context)
        boolean ret = false;
        String name = a.getName();
        if (a.isAuthenticated())
            logger.info(String.format("FOUND %s, authorizing...", name));
            ret = userPermissionTable.canAccess("XXXX", context.getExchange().getRequest().getPath().value(), context.getExchange().getRequest().getMethodValue());
            logger.info(String.format("%s access granted: %B", name, ret));
        
        return ret;
    

    @Override
    public Mono<Authentication> authenticate(Authentication authentication) 
        CompletableFuture<UserPermissions> cup;
        Authentication auth;
        String name = null;

        auth = authentication;
        auth.setAuthenticated(false);
        try 
            name = authentication.getName();
            logger.info(String.format("Looking %s in cache...", name));
            userPermissionTable = (UserPermissions)redisCache.opsForValue().get(name);
            if (userPermissionTable == null)
                logger.info(String.format("NOT in cache, authenticating: %s ...", name));
                cup = permissions.getPermissionsForUser(name, authentication.getCredentials().toString());
                userPermissionTable = cup.get(1000, TimeUnit.MILLISECONDS);
                redisCache.opsForValue().set(name, userPermissionTable, userPermissionTable.getTTL(), TimeUnit.MINUTES);
                auth = new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), null);
                logger.info(String.format("Authenticated: %s", name));
            
            else
                auth = new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), null);
                redisCache.expire(name, userPermissionTable.getTTL(), TimeUnit.MINUTES);
            
         catch (Exception e) 
            logger.info(String.format("FAILED to authenticate: %s", name));
        
        return Mono.just(auth);
    

【讨论】:

以上是关于Grails Spring 安全性的主要内容,如果未能解决你的问题,请参考以下文章

Grails:Spring Security 插件对于简单的安全性来说是不是过于强大

没有 Spring 安全性的 Grails 的 OAuth 2.0

/oauth/token 的 URL 映射失败 - Grails 应用程序中的 Spring 安全性 + OAuth

Grails,从 Acegi 升级到 Spring 安全插件

Grails - SSL 和 Spring 安全核心

grails spring安全休息插件