📜 ⬆️ ⬇️

Embedding Spring Security in the ZK + Spring Framework + Hibernate: Part Two

Good day to all. This article is a continuation of the article about how to implement security in a web application. We will take as a basis our application, which was described in both the previous and in this posts.
Work plan:


Let's start everything in order. We will slightly change the tables in which users and their roles were stored, namely: add the id field to the users table. And create a new table called USER_ROLE.
CREATE TABLE user_role (id NUMBER NOT NULL, name VARCHAR2(10 BYTE) NOT NULL) 

Also create a table for organizing the M: 1 bundle, let's call it user_role_list
 CREATE TABLE user_role_list (id_user NUMBER NOT NULL, id_role NUMBER NOT NULL) 

We describe mapping classes. Create a User class with the following content:
 package com.sample.data; import java.io.Serializable; import java.util.Set; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity @Table(name = "USERS") public class User implements Serializable { private static final long serialVersionUID = 1L; @Id private long id; @Column(name = "USERNAME") private String username; @Column(name = "PASSWORD") private String password; @OneToMany(mappedBy = "user", fetch = FetchType.LAZY) Set<Role> roleList; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Set<Role> getRoleList() { return roleList; } public void setRoleList(Set<Role> roleList) { this.roleList = roleList; } } 


We will also need the Role class:
 package com.sample.data; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name = "USER_ROLE") public class Role implements Serializable { private static final long serialVersionUID = 1L; @Id private long id; @Column(name = "NAME") private String name; @ManyToOne(fetch = FetchType.LAZY) @JoinTable(name = "USER_ROLE_LIST", joinColumns = @JoinColumn(name = "ID_ROLE"), inverseJoinColumns = @JoinColumn(name = "ID_USER")) private User user; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } } 

A small explanation of the code: describing the annotation @JoinTable(name = "USER_ROLE_LIST", joinColumns = @JoinColumn(name = "ID_ROLE"), inverseJoinColumns = @JoinColumn(name = "ID_USER")) , we thereby defined it in cross-rat USER_ROLE_LIST with ID_USER and ID_ROLE fields.
Also in the hibernate-config.xml file add:
 <mapping class="com.sample.data.User" /> <mapping class="com.sample.data.Role" /> 

Based on the plan, we will change our authorization form, or rather, instead of the jsp page, we will create a zk page, slightly changing the functionality. We make on the authorization form not user input, but the choice of a user from the list. We will write the index.zul file and put it in the WebContent folder
 <?page id="testZul" title=" "?> <window title="" border="normal" width="500px" mode="modal" position="center" use="ui.component.Login" id="wndLogin"> <html style="color:red" if="${not empty param.login_error}"> <![CDATA[   ,   ,   <br/><br/> <!-- Reason: --> <!-- ${SPRING_SECURITY_LAST_EXCEPTION.message} --> ]]> </html> <groupbox> <h:form id="f" name="f" action="j_spring_security_check" method="POST" xmlns:h="http://www.w3.org/1999/xhtml"> <grid> <rows> <row> : <combobox id="cbUser" name="j_username" hflex="1" value="" /> </row> <row> : <textbox id="p" type="password" name="j_password" hflex="1" value="" /> </row> <row visible="false"> <checkbox id="r" name="_spring_security_remember_me" /> </row> <row spans="2"> <vbox align="center" hflex="1"> <hbox> <h:input type="submit" value="" /> <h:input type="reset" value="" /> </hbox> </vbox> </row> </rows> </grid> </h:form> </groupbox> </window> 

After that we describe our controller, which we specified in the line use = "ui.component.Login"
 package ui.component; import java.util.List; import javax.servlet.ServletContext; import org.springframework.context.ApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; import org.zkoss.zul.Combobox; import org.zkoss.zul.Window; import com.sample.data.User; import com.sample.service.ISecur; public class Login extends Window { private static final long serialVersionUID = 3974533449164635181L; private ISecur userDao; private Combobox cbUser; private List<User> listUser; public void onCreate() { ApplicationContext ctx = WebApplicationContextUtils. getRequiredWebApplicationContext((ServletContext) getDesktop().getWebApp() .getNativeContext()); userDao = (ISecur) ctx.getBean("securImpl"); cbUser = (Combobox) this.getFellow("cbUser"); onOpenCB(); } public void onOpenCB() { if (listUser == null || listUser.size() == 0) { listUser = userDao.findAllUsers(); for (User pers : listUser) { cbUser.appendItem(pers.getUsername()); } } } } 

We describe the interface for working with USERS, USER_ROLE_LIST and USER_ROLE tables, and write its implementation.
Interface ISecur:
 package com.sample.service; import java.util.List; import com.sample.data.User; public interface ISecur { List<User> findAllUsers(); } 

Implementing the SecurImpl Interface
 package com.sample.service; import java.util.List; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import com.sample.data.User; @Repository @Transactional(readOnly = true) public class SecurImpl implements ISecur { private static SessionFactory sessionFactory; //   datasource @Autowired public void setSessionFactory(SessionFactory sessionFactory) { SecurImpl.sessionFactory = sessionFactory; } @SuppressWarnings("unchecked") @Override public List<User> findAllUsers() { return (List<User>) sessionFactory.getCurrentSession().createQuery("from User").list(); } } 

The next and very important step is the redefinition of methods inherited from the AbstractUserDetailsAuthenticationProvider class. This new inherited class, let's call it MyDaoAuthenticationProvider, will contain the logic of our authorization:
 package com.sample.service; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Set; import org.springframework.context.annotation.Bean; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.GrantedAuthorityImpl; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import com.sample.data.Role; @SuppressWarnings("deprecation") @Service("myDaoAuthenticationProvider") public class MyDaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { @Bean public ISecur userDao() { return new SecurImpl(); } public Authentication authenticate(Authentication authentication) throws AuthenticationException { System.out.println(authentication.getName() + " " + new Date()); return super.authenticate(authentication); } @Override protected void additionalAuthenticationChecks(UserDetails arg0, UsernamePasswordAuthenticationToken arg1) throws AuthenticationException { } @Override protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken userInfo) throws AuthenticationException { List<com.sample.data.User> listUser = userDao().findAllUsers(); User user; if (listUser.size() == 0) { throw new UsernameNotFoundException("    "); } com.sample.data.User person = getUser(listUser, username); if(person.getPassword().equals(userInfo.getCredentials().toString())) { user = new User(person.getUsername(), userInfo.getCredentials().toString(), true, true, true, true, getAuthorities((Set<Role>) person.getRoleList())); } else { user = new User(person.getPassword(), userInfo.getCredentials().toString(), true, true, true, false, getAuthorities("IS_AUTHENTICATED_ANONYMOUSLY")); } return user; } private com.sample.data.User getUser(List<com.sample.data.User> lp, String userName) { com.sample.data.User pers = null; for (com.sample.data.User p : lp) { if (userName.equals(p.getUsername())) { pers = p; } } return pers; } private Collection<GrantedAuthority> getAuthorities(Set<Role> set) { Collection<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(); for (Role role : set) { authList.add(new GrantedAuthorityImpl(role.getName())); } return authList; } private Collection<GrantedAuthority> getAuthorities(String grant_name) { Collection<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(); authList.add(new GrantedAuthorityImpl(grant_name)); return authList; } } 

The protected UserDetails retrieveUser method is invoked when the “Enter” button is clicked.
In this method, we compare the selected user for compliance with the entered password, and if everything is fine, then we create the User class, which is an implementation of the UserDetails interface, and will contain all the necessary information about the user (his login, password and list of rights).
Now let us specify the AuthenticationManager to use our MyDaoAuthenticationProvider class as a provider. For this, in the spring-config.xml file instead of the lines:
 <security:authentication-manager> <security:authentication-provider> <security:jdbc-user-service data-source-ref="dataSource" /> </security:authentication-provider> </security:authentication-manager> 

write the following:
 <security:authentication-manager> <security:authentication-provider ref="userDetailsService"> </security:authentication-provider> </security:authentication-manager> 

It is also very, very important to change the http configuration, which is described here to the following:
 <security:http auto-config="true" use-expressions="true"> <security:intercept-url pattern="/index.zul" access="hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')" /> <security:intercept-url pattern="/login.zul" access="permitAll" /> <security:form-login login-page="/login.zul" always-use-default-target="true" default-target-url="/index.zul" authentication-failure-url="/login.zul?login_error=1" /> </security:http> 

That's all! If you run our application, we will see a beautiful authorization form, with the ability to select a user from the drop-down list.
Thank you all for your attention.

')

Source: https://habr.com/ru/post/129733/


All Articles