Spring security authentication based on request parameter

前端 未结 2 701
盖世英雄少女心
盖世英雄少女心 2020-12-13 16:06

The application I\'m working on already has Spring Security to handle form based authentication. Now the requirement is to login a user programmatically via an external serv

相关标签:
2条回答
  • 2020-12-13 16:44

    If you use Spring MVC controller or service, where targe request parameter is passed, then you can use @PreAuthorize Spring security annotation.

    Say, you have some Spring service that can check passed token and perform authentication if passed token is valid one:

    @Service("authenticator")
    class Authenticator {        
    ...
    public boolean checkTokenAndAuthenticate(Object token) {
        ...
        //check token and if it is invalid return "false"
        ...
        //if token is valid then perform programmatically authentication and return "true"  
    }
    ...             
    }    
    

    Then, with Spring security @PreAuthorize annotation you can do this it next way:

    ...
    @PreAuthorize("@authenticator.checkTokenAndAuthenticate(#token)")
    public Object methodToBeChecked(Object token) { ... }
    ...
    

    Also, you should enable Spring security annotations by and add spring-security-aspects to POM (or jar to classpath).

    0 讨论(0)
  • 2020-12-13 16:54

    I have a similar setup in my application. Here are the basic elements as far as I can tell:

    You need to create an AuthenticationProvider like so:

    public class TokenAuthenticationProvider implements AuthenticationProvider {
    
        @Autowired private SomeService userSvc;
    
        @Override
        public Authentication authenticate(Authentication auth) throws AuthenticationException {
            if (auth.isAuthenticated())
                return auth;
    
            String token = auth.getCredentials().toString();
            User user = userSvc.validateApiAuthenticationToken(token);
            if (user != null) {
                auth = new PreAuthenticatedAuthenticationToken(user, token);
                auth.setAuthenticated(true);
                logger.debug("Token authentication. Token: " + token + "; user: " + user.getDisplayName());
            } else
                throw new BadCredentialsException("Invalid token " + token);
            return auth;
        }
    }
    

    You also need to create a Filter to turn the custom parameter into an authentication token:

    public class AuthenticationTokenFilter implements Filter {
    
    
        @Override
        public void init(FilterConfig fc) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain fc) throws IOException, ServletException {
            SecurityContext context = SecurityContextHolder.getContext();
            if (context.getAuthentication() != null && context.getAuthentication().isAuthenticated()) {
                // do nothing
            } else {
                Map<String,String[]> params = req.getParameterMap();
                if (!params.isEmpty() && params.containsKey("auth_token")) {
                    String token = params.get("auth_token")[0];
                    if (token != null) {
                        Authentication auth = new TokenAuthentication(token);
                        SecurityContextHolder.getContext().setAuthentication(auth);
                    }
                }
            }
    
            fc.doFilter(req, res);
        }
    
        @Override
        public void destroy() {
    
        }
    
        class TokenAuthentication implements Authentication {
            private String token;
            private TokenAuthentication(String token) {
                this.token = token;
            }
            @Override
            public Collection<? extends GrantedAuthority> getAuthorities() {
                return new ArrayList<GrantedAuthority>(0);
            }
            @Override
            public Object getCredentials() {
                return token;
            }
            @Override
            public Object getDetails() {
                return null;
            }
            @Override
            public Object getPrincipal() {
                return null;
            }
            @Override
            public boolean isAuthenticated() {
                return false;
            }
            @Override
            public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
            }
            @Override
            public String getName() {
                // your custom logic here
            }
        }
    
     }
    

    You need to create beans for these:

    <beans:bean id="authTokenFilter" class="com.example.security.AuthenticationTokenFilter" scope="singleton" />
    <beans:bean id="tokenAuthProvider" class="com.example.security.TokenAuthenticationProvider" />
    

    Finally, you need to wire these beans into your security config (adjust accordingly):

    <sec:http >
       <!-- other configs here -->
       <sec:custom-filter ref="authTokenFilter" after="BASIC_AUTH_FILTER" /> <!-- or other appropriate filter -->
    </sec:http>
    
    <sec:authentication-manager>
        <!-- other configs here -->
        <sec:authentication-provider ref="tokenAuthProvider" />
    </sec:authentication-manager>
    

    There might be another way, but this definitely works (using Spring Security 3.1 at the moment).

    0 讨论(0)
提交回复
热议问题