เมื่อใช้ Spring Security วิธีที่เหมาะสมในการรับข้อมูลชื่อผู้ใช้ปัจจุบัน (เช่น SecurityContext) ในถั่วคืออะไร


288

ฉันมีเว็บแอพ Spring MVC ซึ่งใช้ Spring Security ฉันต้องการทราบชื่อผู้ใช้ของผู้ใช้ที่เข้าสู่ระบบในปัจจุบัน ฉันใช้ข้อมูลโค้ดที่ระบุด้านล่าง นี่เป็นวิธีที่ยอมรับหรือไม่

ฉันไม่ชอบการเรียกใช้วิธีการคงที่ภายในตัวควบคุมนี้ - ที่เอาชนะวัตถุประสงค์ทั้งหมดของฤดูใบไม้ผลิ IMHO มีวิธีในการกำหนดค่าแอพเพื่อให้มี SecurityContext ปัจจุบันหรือการตรวจสอบความถูกต้องปัจจุบันถูกฉีดแทนหรือไม่?

  @RequestMapping(method = RequestMethod.GET)
  public ModelAndView showResults(final HttpServletRequest request...) {
    final String currentUser = SecurityContextHolder.getContext().getAuthentication().getName();
    ...
  }

ทำไมคุณไม่มีตัวควบคุม (ตัวควบคุมความปลอดภัย) ในฐานะซูเปอร์คลาสรับผู้ใช้จาก SecurityContext และตั้งเป็นตัวแปรอินสแตนซ์ภายในคลาสนั้น? วิธีนี้เมื่อคุณขยายคอนโทรลเลอร์ที่ปลอดภัยคลาสทั้งหมดของคุณจะสามารถเข้าถึงผู้ใช้หลักของบริบทปัจจุบันได้
Dehan de Croos

คำตอบ:


259

หากคุณใช้Spring 3วิธีที่ง่ายที่สุดคือ:

 @RequestMapping(method = RequestMethod.GET)   
 public ModelAndView showResults(final HttpServletRequest request, Principal principal) {

     final String currentUser = principal.getName();

 }

69

มีการเปลี่ยนแปลงมากมายในโลกฤดูใบไม้ผลิตั้งแต่ตอบคำถามนี้ Spring ทำให้ผู้ใช้ปัจจุบันอยู่ในคอนโทรลเลอร์ได้ง่ายขึ้น สำหรับถั่วอื่น ๆ สปริงได้นำคำแนะนำของผู้เขียนและทำให้การฉีด 'SecurityContextHolder' ง่ายขึ้น รายละเอียดเพิ่มเติมอยู่ในความคิดเห็น


นี่คือทางออกที่ฉันได้ไปด้วย แทนที่จะใช้SecurityContextHolderในตัวควบคุมของฉันฉันต้องการฉีดสิ่งที่ใช้SecurityContextHolderภายใต้ประทุน ฉันไม่พบวิธีที่จะทำสิ่งนี้นอกจากใช้งานอินเทอร์เฟซของฉันเอง:

public interface SecurityContextFacade {

  SecurityContext getContext();

  void setContext(SecurityContext securityContext);

}

ตอนนี้ผู้ควบคุมของฉัน (หรืออะไรก็ตามที่ POJO) จะมีลักษณะเช่นนี้:

public class FooController {

  private final SecurityContextFacade securityContextFacade;

  public FooController(SecurityContextFacade securityContextFacade) {
    this.securityContextFacade = securityContextFacade;
  }

  public void doSomething(){
    SecurityContext context = securityContextFacade.getContext();
    // do something w/ context
  }

}

และเนื่องจากอินเทอร์เฟซเป็นจุดแยกการทดสอบจึงตรงไปตรงมา ในตัวอย่างนี้ฉันใช้ Mockito:

public class FooControllerTest {

  private FooController controller;
  private SecurityContextFacade mockSecurityContextFacade;
  private SecurityContext mockSecurityContext;

  @Before
  public void setUp() throws Exception {
    mockSecurityContextFacade = mock(SecurityContextFacade.class);
    mockSecurityContext = mock(SecurityContext.class);
    stub(mockSecurityContextFacade.getContext()).toReturn(mockSecurityContext);
    controller = new FooController(mockSecurityContextFacade);
  }

  @Test
  public void testDoSomething() {
    controller.doSomething();
    verify(mockSecurityContextFacade).getContext();
  }

}

การใช้งานเริ่มต้นของอินเทอร์เฟซมีลักษณะดังนี้:

public class SecurityContextHolderFacade implements SecurityContextFacade {

  public SecurityContext getContext() {
    return SecurityContextHolder.getContext();
  }

  public void setContext(SecurityContext securityContext) {
    SecurityContextHolder.setContext(securityContext);
  }

}

และในที่สุดการกำหนดค่าการผลิตฤดูใบไม้ผลิมีลักษณะเช่นนี้:

<bean id="myController" class="com.foo.FooController">
     ...
  <constructor-arg index="1">
    <bean class="com.foo.SecurityContextHolderFacade">
  </constructor-arg>
</bean>

ดูเหมือนว่าโง่ไปกว่านั้นที่สปริงซึ่งเป็นภาชนะฉีดของทุกสิ่งไม่ได้ให้วิธีการฉีดสิ่งที่คล้ายกัน ฉันเข้าใจว่าSecurityContextHolderสืบทอดมาจาก acegi แต่ถึงกระนั้น สิ่งคือพวกเขาอยู่ใกล้ - ถ้าSecurityContextHolderมีเพียงทะเยอทะยานที่จะได้รับSecurityContextHolderStrategyอินสแตนซ์พื้นฐาน(ซึ่งเป็นอินเทอร์เฟซ) คุณสามารถฉีดที่ ในความเป็นจริงฉันยังเปิดปัญหาจิรากับผลกระทบนั้น

สิ่งหนึ่งที่สุดท้าย - ฉันเพิ่งเปลี่ยนคำตอบที่ฉันเคยมีที่นี่มาก่อน ตรวจสอบประวัติถ้าคุณอยากรู้ แต่ในฐานะเพื่อนร่วมงานชี้ให้ฉันคำตอบก่อนหน้าของฉันจะไม่ทำงานในสภาพแวดล้อมแบบมัลติเธรด ที่อยู่ภายใต้SecurityContextHolderStrategyการใช้งานโดยSecurityContextHolderมีค่าเริ่มต้นเป็นตัวอย่างของThreadLocalSecurityContextHolderStrategyที่ร้านค้าSecurityContexts ThreadLocalใน ดังนั้นจึงไม่ใช่ความคิดที่ดีที่จะฉีดSecurityContextเข้าไปใน bean โดยตรงในเวลาเริ่มต้น - อาจจำเป็นต้องดึงข้อมูลจากThreadLocalแต่ละครั้งในสภาพแวดล้อมแบบมัลติเธรดดังนั้นจึงเรียกข้อมูลที่ถูกต้องได้


1
ฉันชอบโซลูชันของคุณ - เป็นการใช้งานที่ชาญฉลาดของการสนับสนุนวิธีการจากโรงงานใน Spring ที่กล่าวมาสิ่งนี้ใช้งานได้กับคุณเพราะวัตถุคอนโทรลเลอร์นั้นถูกกำหนดขอบเขตตามคำขอของเว็บ หากคุณเปลี่ยนขอบเขตของคอนโทรลเลอร์ bean ในวิธีที่ไม่ถูกต้องสิ่งนี้จะแตก
Paul Morie

2
ความคิดเห็นสองข้อก่อนหน้านี้อ้างถึงคำตอบเก่า ๆ ที่ไม่ถูกต้องซึ่งฉันเพิ่งเปลี่ยนไป
สกอตต์เบล

12
นี่ยังเป็นโซลูชันที่แนะนำสำหรับการเปิดตัว Spring ปัจจุบันหรือไม่ ฉันไม่อยากจะเชื่อเลยว่าต้องการรหัสมากเพียงเพื่อเรียกคืนชื่อผู้ใช้
Ta Sas

6
หากคุณใช้ Spring Security 3.0.x พวกเขานำข้อเสนอแนะของฉันไปใช้กับปัญหา JIRA ที่ฉันบันทึกไว้jira.springsource.org/browse/SEC-1188ดังนั้นตอนนี้คุณสามารถฉีดอินสแตนซ์ของ สปริงกำหนดค่า
Scott Bale

4
โปรดดูคำตอบ tsunade21 Spring 3 ตอนนี้อนุญาตให้คุณใช้ java.security.Principal เป็นอาร์กิวเมนต์เมธอดในคอนโทรลเลอร์ของคุณ
Patrick

22

ฉันยอมรับว่าต้องสอบถาม SecurityContext สำหรับผู้ใช้ปัจจุบันเหม็นดูเหมือนจะเป็นวิธียกเลิกการจัดการปัญหานี้

ฉันเขียนคลาส "ตัวช่วย" แบบคงที่เพื่อจัดการกับปัญหานี้ มันสกปรกในการที่มันเป็นวิธีสากลและคงที่ แต่ฉันคิดวิธีนี้ถ้าเราเปลี่ยนแปลงสิ่งที่เกี่ยวข้องกับความปลอดภัยอย่างน้อยฉันก็ต้องเปลี่ยนรายละเอียดในที่เดียว:

/**
* Returns the domain User object for the currently logged in user, or null
* if no User is logged in.
* 
* @return User object for the currently logged in user, or null if no User
*         is logged in.
*/
public static User getCurrentUser() {

    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal()

    if (principal instanceof MyUserDetails) return ((MyUserDetails) principal).getUser();

    // principal object is either null or represents anonymous user -
    // neither of which our domain User object can represent - so return null
    return null;
}


/**
 * Utility method to determine if the current user is logged in /
 * authenticated.
 * <p>
 * Equivalent of calling:
 * <p>
 * <code>getCurrentUser() != null</code>
 * 
 * @return if user is logged in
 */
public static boolean isLoggedIn() {
    return getCurrentUser() != null;
}

22
เป็นตราบเท่าที่ SecurityContextHolder.getContext () เป็นและหลังเป็น threadsafe เนื่องจากจะเก็บรายละเอียดความปลอดภัยใน threadLocal รหัสนี้ไม่มีสถานะ
matt b

22

เพื่อให้มันแสดงในหน้า JSP ของคุณคุณสามารถใช้ Spring Security Tag Lib:

http://static.springsource.org/spring-security/site/docs/3.0.x/reference/taglibs.html

ในการใช้แท็กใด ๆ คุณต้องมี taglib ความปลอดภัยที่ประกาศใน JSP ของคุณ:

<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>

จากนั้นในหน้า jsp ทำสิ่งนี้:

<security:authorize access="isAuthenticated()">
    logged in as <security:authentication property="principal.username" /> 
</security:authorize>

<security:authorize access="! isAuthenticated()">
    not logged in
</security:authorize>

หมายเหตุ: ดังที่กล่าวไว้ในความคิดเห็นโดย @ SBerg413 คุณจะต้องเพิ่ม

ใช้การแสดงออก = "true"

ไปที่แท็ก "http" ในการกำหนดค่า security.xml เพื่อให้ใช้งานได้


ดูเหมือนว่าเป็นวิธีที่ได้รับการรับรองความปลอดภัยของสปริง!
Nick Spacek

3
เพื่อให้วิธีนี้ใช้งานได้คุณต้องเพิ่ม use-expressions = "true" ในแท็ก http ในการกำหนดค่า security.xml
SBerg413

ขอบคุณ @ SBerg413 ฉันจะแก้ไขคำตอบของฉันและเพิ่มคำอธิบายที่สำคัญของคุณ!
Brad Parks

14

หากคุณใช้ Spring Security ver> = 3.2 คุณสามารถใช้@AuthenticationPrincipalคำอธิบายประกอบได้:

@RequestMapping(method = RequestMethod.GET)
public ModelAndView showResults(@AuthenticationPrincipal CustomUser currentUser, HttpServletRequest request) {
    String currentUsername = currentUser.getUsername();
    // ...
}

ที่นี่CustomUserเป็นวัตถุที่กำหนดเองที่ใช้งานUserDetailsที่ถูกส่งคืนโดยที่กำหนดเองUserDetailsServiceที่ถูกส่งกลับโดยกำหนดเอง

สามารถดูข้อมูลเพิ่มเติมได้ในบท@AuthenticationPrincipalของเอกสารอ้างอิง Spring Security


13

ฉันได้รับผู้ใช้รับรองความถูกต้องโดย HttpServletRequest.getUserPrincipal ();

ตัวอย่าง:

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.support.RequestContext;

import foo.Form;

@Controller
@RequestMapping(value="/welcome")
public class IndexController {

    @RequestMapping(method=RequestMethod.GET)
    public String getCreateForm(Model model, HttpServletRequest request) {

        if(request.getUserPrincipal() != null) {
            String loginName = request.getUserPrincipal().getName();
            System.out.println("loginName : " + loginName );
        }

        model.addAttribute("form", new Form());
        return "welcome";
    }
}

ฉันชอบทางออกของคุณ ถึงผู้เชี่ยวชาญของ Spring: นั่นเป็นทางออกที่ดีหรือไม่?
marioosh

ไม่ใช่ทางออกที่ดี คุณจะได้รับnullหากผู้ใช้ได้รับการพิสูจน์ตัวตนโดยไม่ระบุชื่อ ( http> anonymousองค์ประกอบใน Spring Security XML) SecurityContextHolderหรือSecurityContextHolderStrategyเป็นวิธีที่เหมาะสม
Nowaker

1
เพื่อให้ฉันได้ตรวจสอบว่าไม่ใช่ null request.getUserPrincipal ()! = null
digz6666

เป็นโมฆะในตัวกรอง
Alex78191

9

ใน Spring 3+ คุณมีตัวเลือกดังต่อไปนี้

ตัวเลือกที่ 1 :

@RequestMapping(method = RequestMethod.GET)    
public String currentUserNameByPrincipal(Principal principal) {
    return principal.getName();
}

ตัวเลือก 2:

@RequestMapping(method = RequestMethod.GET)
public String currentUserNameByAuthentication(Authentication authentication) {
    return authentication.getName();
}

ตัวเลือก 3:

@RequestMapping(method = RequestMethod.GET)    
public String currentUserByHTTPRequest(HttpServletRequest request) {
    return request.getUserPrincipal().getName();

}

ตัวเลือก 4: แฟนซีอันหนึ่ง: ลองดูรายละเอียดเพิ่มเติม

public ModelAndView someRequestHandler(@ActiveUser User activeUser) {
  ...
}

1
สปริง 3.2 การรักษาความปลอดภัย - เว็บมาพร้อมกับ@CurrentUserสิ่งที่ทำงานเหมือนกับที่กำหนดเอง@ActiveUserจากลิงค์ของคุณ
Mike Partridge

@ MikePartridge ฉันดูเหมือนจะไม่พบสิ่งที่คุณพูดลิงค์ใด ๆ ?? หรือข้อมูลเพิ่มเติม ??
azerafati

1
ความผิดพลาดของฉัน - ฉันเข้าใจผิดว่า Spring Security AuthenticationPrincipalArgumentResolver javadoc ตัวอย่างแสดงให้เห็นว่ามีการตัดคำอธิบายประกอบที่@AuthenticationPrincipalกำหนดเอง @CurrentUserตั้งแต่ 3.2 เราไม่จำเป็นต้องใช้ตัวแก้ไขอาร์กิวเมนต์ที่กำหนดเองเช่นเดียวกับในคำตอบที่เชื่อมโยง คำตอบอื่น ๆ นี้มีรายละเอียดเพิ่มเติม
Mike Partridge

5

ใช่สถิตโดยทั่วไปมักจะไม่ดี - โดยทั่วไป แต่ในกรณีนี้สแตติกเป็นรหัสที่ปลอดภัยที่สุดที่คุณสามารถเขียนได้ เนื่องจากบริบทความปลอดภัยจะเชื่อมโยงหลักการกับเธรดที่รันอยู่ในปัจจุบันรหัสที่ปลอดภัยที่สุดจะเข้าถึงสแตติกจากเธรดให้มากที่สุดโดยตรง การซ่อนการเข้าถึงด้านหลังคลาส wrapper ที่ถูกฉีดจะช่วยให้ผู้โจมตีมีคะแนนมากขึ้นในการโจมตี พวกเขาไม่ต้องการการเข้าถึงโค้ด (ซึ่งพวกเขาอาจมีการเปลี่ยนแปลงยากหากลงนาม jar) พวกเขาต้องการวิธีการแทนที่การกำหนดค่าซึ่งสามารถทำได้ในขณะรันไทม์หรือวาง XML ลงบน classpath แม้กระทั่งการใช้การฉีดหมายเหตุประกอบในรหัสที่ลงนามแล้วก็สามารถ overridable กับ XML ภายนอกได้ XML ดังกล่าวสามารถฉีดระบบที่กำลังรันด้วยหลักการโกง


5

ฉันจะทำสิ่งนี้:

request.getRemoteUser();

1
ที่อาจใช้งานได้ แต่ไม่น่าเชื่อถือ จาก javadoc: "การที่ชื่อผู้ใช้จะถูกส่งไปพร้อมกับคำขอแต่ละครั้งนั้นขึ้นอยู่กับเบราว์เซอร์และประเภทของการตรวจสอบสิทธิ์" - download-llnw.oracle.com/javaee/6/api/javax/servlet/http/…
Scott Bale

3
นี่เป็นวิธีที่ถูกต้องและง่ายมากในการรับชื่อผู้ใช้ระยะไกลในเว็บแอปพลิเคชัน Spring Security ห่วงโซ่กรองมาตรฐานรวมถึงการSecurityContextHolderAwareRequestFilterที่ wraps SecurityContextHolderคำขอและการดำเนินการสายนี้โดยการเข้าถึง
Shaun the Sheep

4

สำหรับแอป Spring MVC ล่าสุดที่ฉันเขียนฉันไม่ได้ฉีดผู้ถือ SecurityContext แต่ฉันมีตัวควบคุมพื้นฐานที่ฉันมีสองวิธีอรรถประโยชน์ที่เกี่ยวข้องกับสิ่งนี้ ... isAuthenticated () & getUsername () ภายในพวกเขาจะเรียกวิธีการคงที่คุณอธิบาย

อย่างน้อยก็เป็นเพียงครั้งเดียวถ้าคุณต้องการ refactor ในภายหลัง


3

คุณสามารถใช้ Spring AOP aproach ได้ ตัวอย่างเช่นหากคุณมีบริการบางอย่างที่จำเป็นต้องรู้หลักการปัจจุบัน คุณสามารถแนะนำคำอธิบายประกอบที่กำหนดเองเช่น @Principal ซึ่งระบุว่าบริการนี้ควรขึ้นอยู่กับเงินต้น

public class SomeService {
    private String principal;
    @Principal
    public setPrincipal(String principal){
        this.principal=principal;
    }
}

จากนั้นในคำแนะนำของคุณซึ่งฉันคิดว่าจำเป็นต้องขยาย MethodBeforeAdvice ตรวจสอบว่าบริการเฉพาะมีคำอธิบายประกอบ @Principal และฉีดชื่อหลักหรือตั้งเป็น 'ANONYMOUS' แทน


ฉันจำเป็นต้องเข้าถึงอาจารย์ใหญ่ในระดับบริการคุณสามารถโพสต์ตัวอย่างที่สมบูรณ์ใน GitHub ได้หรือไม่? ฉันไม่รู้สปริง AOP ดังนั้นจึงขอร้อง
Rakesh Waghela

2

ปัญหาเดียวคือแม้ว่าหลังจากการรับรองความถูกต้องกับ Spring Security แล้วผู้ใช้ / หลัก bean ไม่มีอยู่ในคอนเทนเนอร์ดังนั้นการฉีดพึ่งพามันจะยาก ก่อนที่เราจะใช้สปริงซีเคียวริตี้เราจะสร้างเซสชั่นแบบ จำกัด ขอบเขตที่มีอาจารย์ใหญ่ในปัจจุบันให้ฉีดเข้าไปใน "AuthService" แล้วฉีดบริการนั้นลงในบริการอื่น ๆ ในแอปพลิเคชัน ดังนั้นบริการเหล่านั้นก็จะเรียก authService.getCurrentUser () เพื่อรับวัตถุ หากคุณมีสถานที่ในรหัสของคุณที่คุณได้รับการอ้างอิงถึงอาจารย์ใหญ่คนเดียวกันในเซสชั่นคุณสามารถตั้งเป็นสถานที่ให้บริการในถั่วขอบเขตเซสชั่นของคุณ


1

ลองสิ่งนี้

การพิสูจน์ตัวตนการพิสูจน์ตัวตน = SecurityContextHolder.getContext (). getAuthentication ();
String ชื่อผู้ใช้ = authentication.getName ();


3
การเรียก SecurityContextHolder.getContext () วิธีการคงที่เป็นสิ่งที่ฉันบ่นเกี่ยวกับในคำถามเดิม คุณยังไม่ได้ตอบอะไรเลย
Scott Bale

2
อย่างไรก็ตามเป็นสิ่งที่เอกสารแนะนำ: static.springsource.org/spring-security/site/docs/3.0.x/… ดังนั้นสิ่งที่คุณประสบความสำเร็จโดยการหลีกเลี่ยงมันได้หรือไม่ คุณกำลังมองหาวิธีแก้ปัญหาที่ซับซ้อนเพื่อแก้ไขปัญหาอย่างง่าย ที่ดีที่สุด - คุณจะได้รับพฤติกรรมเดียวกัน ที่แย่ที่สุดคุณจะได้รับบั๊กหรือช่องโหว่ด้านความปลอดภัย
Bob Kerns

2
@BobKerns สำหรับการทดสอบมันสะอาดกว่าที่จะสามารถฉีดการรับรองความถูกต้องเมื่อเทียบกับการวางไว้ในเธรดโลคัล

1

ทางออกที่ดีที่สุดถ้าคุณใช้ Spring 3 และต้องการหลักการที่ได้รับการรับรองในคอนโทรลเลอร์ของคุณคือทำสิ่งนี้:

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;

    @Controller
    public class KnoteController {
        @RequestMapping(method = RequestMethod.GET)
        public java.lang.String list(Model uiModel, UsernamePasswordAuthenticationToken authToken) {

            if (authToken instanceof UsernamePasswordAuthenticationToken) {
                user = (User) authToken.getPrincipal();
            }
            ...

    }

1
ทำไมคุณถึงทำเช่นนั้นกับ UsernamePasswordAuthenticationToken ตรวจสอบว่าพารามิเตอร์เป็นประเภท UsernamePasswordAuthenticationToken อยู่แล้ว?
Scott Bale

(อินสแตนซ์ authToken ของ UsernamePasswordAuthenticationToken) เทียบเท่ากับการทำงานของ if (authToken! = null) หลังอาจจะสะอาดกว่าเล็กน้อย แต่ก็ไม่มีความแตกต่าง
ทำเครื่องหมาย

1

ฉันกำลังใช้@AuthenticationPrincipalคำอธิบายประกอบใน@Controllerชั้นเรียนเช่นเดียวกับใน@ControllerAdvicerคำอธิบายประกอบ อดีต .:

@ControllerAdvice
public class ControllerAdvicer
{
    private static final Logger LOGGER = LoggerFactory.getLogger(ControllerAdvicer.class);


    @ModelAttribute("userActive")
    public UserActive currentUser(@AuthenticationPrincipal UserActive currentUser)
    {
        return currentUser;
    }
}

ในกรณีที่เป็นชั้นที่ผมใช้สำหรับการให้บริการผู้ใช้ลงทะเบียนและยื่นออกมาจากUserActive org.springframework.security.core.userdetails.Userสิ่งที่ต้องการ:

public class UserActive extends org.springframework.security.core.userdetails.User
{

    private final User user;

    public UserActive(User user)
    {
        super(user.getUsername(), user.getPasswordHash(), user.getGrantedAuthorities());
        this.user = user;
    }

     //More functions
}

ง่ายจริงๆ


0

กำหนดPrincipalว่าเป็นการพึ่งพาในวิธีการควบคุมของคุณและสปริงจะฉีดผู้ใช้ที่ได้รับการรับรองในปัจจุบันในวิธีการของคุณเมื่อมีการร้องขอ


-2

ฉันต้องการแบ่งปันวิธีการสนับสนุนรายละเอียดผู้ใช้ในหน้า freemarker ทุกอย่างเรียบง่ายและทำงานได้อย่างสมบูรณ์แบบ!

คุณต้องทำการตรวจสอบสิทธิ์ซ้ำอีกครั้งdefault-target-url(หน้าหลังฟอร์มล็อกอิน) นี่คือวิธีการควบคุมของฉันสำหรับหน้านั้น:

@RequestMapping(value = "/monitoring", method = RequestMethod.GET)
public ModelAndView getMonitoringPage(Model model, final HttpServletRequest request) {
    showRequestLog("monitoring");


    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    String userName = authentication.getName();
    //create a new session
    HttpSession session = request.getSession(true);
    session.setAttribute("username", userName);

    return new ModelAndView(catalogPath + "monitoring");
}

และนี่คือรหัส ftl ของฉัน:

<@security.authorize ifAnyGranted="ROLE_ADMIN, ROLE_USER">
<p style="padding-right: 20px;">Logged in as ${username!"Anonymous" }</p>
</@security.authorize> 

และนั่นคือชื่อผู้ใช้จะปรากฏในทุกหน้าหลังจากได้รับอนุญาต


ขอบคุณที่พยายามตอบ แต่การใช้วิธีคงที่ SecurityContextHolder.getContext () เป็นสิ่งที่ฉันต้องการหลีกเลี่ยงและเหตุผลที่ฉันถามคำถามนี้ตั้งแต่แรก
Scott Bale
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.