繁体   English   中英

使用带有AJAX身份验证的Spring Security保护Rest API

[英]Securing Rest API using Spring Security with AJAX Authentication

我在为Webapp设置AJAX Calls的安全性时遇到麻烦,该Webapp在后端使用Spring Security验证我的请求。

我的应用程序中有某些端点,如下所示,并且正在通过网站和移动应用程序(Andriod,iOS)访问它们。

我现在为所有/ api / *网址添加了基本身份验证,但是在Mobile Apps Access的情况下很好,但是如果我在网站上的AJAX调用中使用相同的身份验证,那么我需要传递用户名和密码作为标题请求,例如在此链接中 ,但我不想向外界透露用户名和密码,因为任何人都可以通过在JS文件上执行查看源来看到它们。

现在,我想要的是任何具有ROLE_API的用户名和密码都可以访问/ api / * urls 但是,当从网站访问这些URL时,如何以一种安全的方式传递用户名和密码,当我需要使用来自我的网站的AJAX请求进行任何CRUD操作时,其他任何URL都无法访问/ api / * url

以下是我的security-config.xml,AuthenticationManager和Controller的代码。

spring-security.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/security 
http://www.springframework.org/schema/security/spring-security-3.2.xsd">


<security:http auto-config="false" use-expressions="true"
    access-denied-page="/login" entry-point-ref="authenticationEntryPoint">
<security:intercept-url pattern="/login" access="permitAll"/>
<security:intercept-url pattern="/api/**" access="hasRole('ROLE_API')"/>
<security:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')"/>
<security:intercept-url pattern="/user/**" access="hasRole('ROLE_USER')"/>
<security:logout invalidate-session="true" logout-success-url="/login" logout-url="/logout" />
<security:custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER" />
<security:custom-filter ref="authenticationFilter" position="BASIC_AUTH_FILTER" />
</security:http>

<security:global-method-security secured-annotations="enabled" />

<bean id="authenticationFilter"
    class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"
    p:authenticationManager-ref="customAuthenticationManager"
    p:authenticationFailureHandler-ref="customAuthenticationFailureHandler"
    p:authenticationSuccessHandler-ref="customAuthenticationSuccessHandler" />

<bean id="customAuthenticationManager"
    class="com.lumin.mytalk.authentication.CustomAuthenticationManager" />

<bean id="customAuthenticationFailureHandler"
    class="com.lumin.mytalk.authentication.AuthenticationFailureUrlHandler" />

<bean id="customAuthenticationSuccessHandler"
    class="com.lumin.mytalk.authentication.AuthenticationUrlHandler" />

<bean id="authenticationEntryPoint"
    class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"
    p:loginFormUrl="/login" />

    <security:authentication-manager />
</beans>

CustomAuthenticationManager.java

public class CustomAuthenticationManager implements AuthenticationManager {
protected static Logger logger = Logger
        .getLogger(CustomAuthenticationManager.class.getName());

@Autowired
private UserService userService;

private Md5PasswordEncoder passwordEncoder = new Md5PasswordEncoder();

public Authentication authenticate(Authentication auth)
        throws AuthenticationException {

    System.out.println("Performing custom authentication");

    // Init a database user object
    User user = null;
    if (auth != null && auth.getName() != null && !auth.getName().equals("")) {
        try {
            // Retrieve user details from database
            String username = auth.getName();
            user = userService.getByEmail(username);
        } catch (Exception e) {
            System.out.println("User does not exists!");
            throw new BadCredentialsException("User does not exists!");
        }

        if(user.getIsSocialUser() != null && user.getIsSocialUser()){
            return new UsernamePasswordAuthenticationToken(auth.getName(), null, getAuthorities(user.getRole()));
        }else{
            String pwd = (String) auth.getCredentials();
            if (passwordEncoder.encodePassword(pwd, null).equals(
                    user.getPassword())) {
                System.out.println("Correct Password!");
                System.out.println("User details are good and ready to go");
                return new UsernamePasswordAuthenticationToken(auth.getName(), auth.getCredentials(), getAuthorities(user.getRole()));
            } else {
                System.out.println("Incorrect Password");
                throw new BadCredentialsException("Incorrect Password !");
            }   
        }
    } else {
        System.out.println("Username and Password are required");
        throw new BadCredentialsException("Username and Password are required !");
    }
}

public Collection<GrantedAuthority> getAuthorities(String role) {
    // Create a list of grants for this user
    List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(0);
    // Check if this user has admin access
    if (role.equals(USERROLE.ROLE_USER.name())) {
        System.out.println("Grant ROLE_USER to this user");
        authList.add(new SimpleGrantedAuthority(USERROLE.ROLE_USER.name()));
    } else if (role.equals(USERROLE.ROLE_ADMIN.name())) {
        System.out.println("Grant ROLE_ADMIN to this user");
        authList.add(new SimpleGrantedAuthority(USERROLE.ROLE_ADMIN.name()));
    }
    // Return list of granted authorities
    return authList;
}
}

样品架控制器

@RestController
public class CategoryController extends AbstractGenericController{

    @Autowired
    private CategoryService categoryService;    

    @ResponseBody
    @RequestMapping(value = Path.Url.API + Path.Url.CATEGORY + Path.OperationUrl.CREATE, method = RequestMethod.POST, produces = { "application/json", "application/xml" })
    public Object create(@RequestBody Category category) {
        Category isExisting = categoryService.getCategoryByName(category.getCategoryName());
        if (isExisting == null) {
            Long id = categoryService.createWithID(category);
            return new Response(null, STATUS.SUCCESS, "Category created successfully. Id :" + id);
        }else{
            return new Response(null, STATUS.FAILURE, "Category already exist. Please use update category function.");
        }
    }
}

用户名和密码可以进行base64编码,并在Authentication标头中传递。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM